• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 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/internal/host/gatt/local_service_manager.h"
16 
17 #include <pw_assert/check.h>
18 #include <pw_bytes/endian.h>
19 
20 #include "pw_bluetooth_sapphire/internal/host/att/att.h"
21 #include "pw_bluetooth_sapphire/internal/host/gatt/gatt_defs.h"
22 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
23 #include "pw_unit_test/framework.h"
24 
25 namespace bt::gatt {
26 namespace {
27 
28 constexpr PeerId kTestPeerId(1);
29 constexpr PeerId kTestPeerId2(2);
30 constexpr UUID kTestType16(uint16_t{0xdead});
31 constexpr UUID kTestType32(uint32_t{0xdeadbeef});
32 
33 // The first characteristic value attribute of the first service has handle
34 // number 3.
35 constexpr att::Handle kFirstChrcValueHandle = 0x0003;
36 
37 // The first descroptor of the first characteristic of the first service has
38 // handle number 4.
39 constexpr att::Handle kFirstDescrHandle = 0x0004;
40 
AllowedNoSecurity()41 inline att::AccessRequirements AllowedNoSecurity() {
42   return att::AccessRequirements(/*encryption=*/false,
43                                  /*authentication=*/false,
44                                  /*authorization=*/false);
45 }
46 
47 // Convenience function that registers |service| with |mgr| using the NOP
48 // handlers above by default.
RegisterService(LocalServiceManager * mgr,ServicePtr service,ReadHandler read_handler=NopReadHandler,WriteHandler write_handler=NopWriteHandler,ClientConfigCallback ccc_callback=NopCCCallback)49 IdType RegisterService(LocalServiceManager* mgr,
50                        ServicePtr service,
51                        ReadHandler read_handler = NopReadHandler,
52                        WriteHandler write_handler = NopWriteHandler,
53                        ClientConfigCallback ccc_callback = NopCCCallback) {
54   return mgr->RegisterService(std::move(service),
55                               std::move(read_handler),
56                               std::move(write_handler),
57                               std::move(ccc_callback));
58 }
59 
TEST(LocalServiceManagerTest,EmptyService)60 TEST(LocalServiceManagerTest, EmptyService) {
61   LocalServiceManager mgr;
62 
63   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
64   auto id1 = RegisterService(&mgr, std::move(service));
65   EXPECT_NE(0u, id1);
66 
67   service = std::make_unique<Service>(/*primary=*/false, kTestType32);
68   auto id2 = RegisterService(&mgr, std::move(service));
69   EXPECT_NE(0u, id2);
70 
71   EXPECT_EQ(2u, mgr.database()->groupings().size());
72 
73   auto iter = mgr.database()->groupings().begin();
74 
75   EXPECT_TRUE(iter->complete());
76   EXPECT_EQ(1u, iter->attributes().size());
77   EXPECT_TRUE(iter->active());
78   EXPECT_EQ(0x0001, iter->start_handle());
79   EXPECT_EQ(0x0001, iter->end_handle());
80   EXPECT_EQ(types::kPrimaryService, iter->group_type());
81   EXPECT_TRUE(
82       ContainersEqual(StaticByteBuffer(0xad, 0xde), iter->decl_value()));
83 
84   iter++;
85 
86   EXPECT_TRUE(iter->complete());
87   EXPECT_EQ(1u, iter->attributes().size());
88   EXPECT_TRUE(iter->active());
89   EXPECT_EQ(0x0002, iter->start_handle());
90   EXPECT_EQ(0x0002, iter->end_handle());
91   EXPECT_EQ(types::kSecondaryService, iter->group_type());
92   EXPECT_TRUE(ContainersEqual(StaticByteBuffer(0xFB,
93                                                0x34,
94                                                0x9B,
95                                                0x5F,
96                                                0x80,
97                                                0x00,
98                                                0x00,
99                                                0x80,
100                                                0x00,
101                                                0x10,
102                                                0x00,
103                                                0x00,
104                                                0xef,
105                                                0xbe,
106                                                0xad,
107                                                0xde),
108                               iter->decl_value()));
109 }
110 
TEST(LocalServiceManagerTest,UnregisterService)111 TEST(LocalServiceManagerTest, UnregisterService) {
112   LocalServiceManager mgr;
113 
114   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
115   auto id1 = RegisterService(&mgr, std::move(service));
116   EXPECT_NE(0u, id1);
117   EXPECT_EQ(1u, mgr.database()->groupings().size());
118 
119   // Unknown id
120   EXPECT_FALSE(mgr.UnregisterService(id1 + 1));
121 
122   // Success
123   EXPECT_TRUE(mgr.UnregisterService(id1));
124   EXPECT_TRUE(mgr.database()->groupings().empty());
125 
126   // |id1| becomes unknown
127   EXPECT_FALSE(mgr.UnregisterService(id1));
128 }
129 
TEST(LocalServiceManagerTest,RegisterCharacteristic)130 TEST(LocalServiceManagerTest, RegisterCharacteristic) {
131   LocalServiceManager mgr;
132 
133   constexpr IdType kChrcId = 0;
134   constexpr uint8_t kChrcProps = Property::kRead;
135   constexpr UUID kTestChrcType(uint16_t{0xabcd});
136   const att::AccessRequirements kReadReqs(/*encryption=*/true,
137                                           /*authentication=*/true,
138                                           /*authorization=*/true);
139   const att::AccessRequirements kWriteReqs, kUpdateReqs;
140 
141   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
142   service->AddCharacteristic(std::make_unique<Characteristic>(kChrcId,
143                                                               kTestChrcType,
144                                                               kChrcProps,
145                                                               0,
146                                                               kReadReqs,
147                                                               kWriteReqs,
148                                                               kUpdateReqs));
149   auto id1 = RegisterService(&mgr, std::move(service));
150   EXPECT_NE(0u, id1);
151 
152   ASSERT_EQ(1u, mgr.database()->groupings().size());
153   const auto& grouping = mgr.database()->groupings().front();
154   EXPECT_TRUE(grouping.complete());
155 
156   const auto& attrs = grouping.attributes();
157   ASSERT_EQ(3u, attrs.size());
158 
159   att::Handle srvc_handle = attrs[0].handle();
160   EXPECT_EQ(att::kHandleMin, srvc_handle);
161 
162   // Characteristic declaration
163   EXPECT_EQ(srvc_handle + 1, attrs[1].handle());
164   EXPECT_EQ(types::kCharacteristicDeclaration, attrs[1].type());
165   EXPECT_EQ(AllowedNoSecurity(), attrs[1].read_reqs());
166   EXPECT_EQ(att::AccessRequirements(), attrs[1].write_reqs());
167   EXPECT_TRUE(attrs[1].value());
168 
169   // clang-format off
170   const StaticByteBuffer kDeclValue(
171       0x02,        // properties
172       0x03, 0x00,  // value handle
173       0xcd, 0xab   // UUID
174   );
175   // clang-format on
176   EXPECT_TRUE(ContainersEqual(kDeclValue, *attrs[1].value()));
177 
178   // Characteristic value
179   EXPECT_EQ(srvc_handle + 2, attrs[2].handle());
180   EXPECT_EQ(kTestChrcType, attrs[2].type());
181   EXPECT_EQ(kReadReqs, attrs[2].read_reqs());
182   EXPECT_EQ(kWriteReqs, attrs[2].write_reqs());
183 
184   // This value is dynamic.
185   EXPECT_FALSE(attrs[2].value());
186 }
187 
TEST(LocalServiceManagerTest,RegisterCharacteristic32)188 TEST(LocalServiceManagerTest, RegisterCharacteristic32) {
189   LocalServiceManager mgr;
190 
191   constexpr IdType kChrcId = 0;
192   constexpr uint8_t kChrcProps = Property::kRead;
193   constexpr UUID kTestChrcType(uint32_t{0xdeadbeef});
194   const att::AccessRequirements kReadReqs(/*encryption=*/true,
195                                           /*authentication=*/true,
196                                           /*authorization=*/true);
197   const att::AccessRequirements kWriteReqs, kUpdateReqs;
198 
199   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
200   service->AddCharacteristic(std::make_unique<Characteristic>(kChrcId,
201                                                               kTestChrcType,
202                                                               kChrcProps,
203                                                               0,
204                                                               kReadReqs,
205                                                               kWriteReqs,
206                                                               kUpdateReqs));
207   auto id1 = RegisterService(&mgr, std::move(service));
208   EXPECT_NE(0u, id1);
209 
210   ASSERT_EQ(1u, mgr.database()->groupings().size());
211   const auto& grouping = mgr.database()->groupings().front();
212   EXPECT_TRUE(grouping.complete());
213 
214   const auto& attrs = grouping.attributes();
215   ASSERT_EQ(3u, attrs.size());
216 
217   att::Handle srvc_handle = attrs[0].handle();
218   EXPECT_EQ(att::kHandleMin, srvc_handle);
219 
220   // Characteristic declaration
221   EXPECT_EQ(srvc_handle + 1, attrs[1].handle());
222   EXPECT_EQ(types::kCharacteristicDeclaration, attrs[1].type());
223   EXPECT_EQ(AllowedNoSecurity(), attrs[1].read_reqs());
224   EXPECT_EQ(att::AccessRequirements(), attrs[1].write_reqs());
225   EXPECT_TRUE(attrs[1].value());
226 
227   const StaticByteBuffer kDeclValue(0x02,  // properties
228                                     0x03,
229                                     0x00,  // value handle
230 
231                                     // The 32-bit UUID will be stored as 128-bit
232                                     0xFB,
233                                     0x34,
234                                     0x9B,
235                                     0x5F,
236                                     0x80,
237                                     0x00,
238                                     0x00,
239                                     0x80,
240                                     0x00,
241                                     0x10,
242                                     0x00,
243                                     0x00,
244                                     0xef,
245                                     0xbe,
246                                     0xad,
247                                     0xde);
248   EXPECT_TRUE(ContainersEqual(kDeclValue, *attrs[1].value()));
249 
250   // Characteristic value
251   EXPECT_EQ(srvc_handle + 2, attrs[2].handle());
252   EXPECT_EQ(kTestChrcType, attrs[2].type());
253   EXPECT_EQ(kReadReqs, attrs[2].read_reqs());
254   EXPECT_EQ(kWriteReqs, attrs[2].write_reqs());
255 
256   // This value is dynamic.
257   EXPECT_FALSE(attrs[2].value());
258 }
259 
TEST(LocalServiceManagerTest,RegisterCharacteristic128)260 TEST(LocalServiceManagerTest, RegisterCharacteristic128) {
261   LocalServiceManager mgr;
262 
263   constexpr IdType kChrcId = 0;
264   constexpr uint8_t kChrcProps = Property::kRead;
265   UUID kTestChrcType;
266   EXPECT_TRUE(
267       StringToUuid("00112233-4455-6677-8899-AABBCCDDEEFF", &kTestChrcType));
268   const att::AccessRequirements kReadReqs(/*encryption=*/true,
269                                           /*authentication=*/true,
270                                           /*authorization=*/true);
271   const att::AccessRequirements kWriteReqs, kUpdateReqs;
272 
273   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
274   service->AddCharacteristic(std::make_unique<Characteristic>(kChrcId,
275                                                               kTestChrcType,
276                                                               kChrcProps,
277                                                               0,
278                                                               kReadReqs,
279                                                               kWriteReqs,
280                                                               kUpdateReqs));
281   auto id1 = RegisterService(&mgr, std::move(service));
282   EXPECT_NE(0u, id1);
283 
284   ASSERT_EQ(1u, mgr.database()->groupings().size());
285   const auto& grouping = mgr.database()->groupings().front();
286   EXPECT_TRUE(grouping.complete());
287 
288   const auto& attrs = grouping.attributes();
289   ASSERT_EQ(3u, attrs.size());
290 
291   att::Handle srvc_handle = attrs[0].handle();
292   EXPECT_EQ(att::kHandleMin, srvc_handle);
293 
294   // Characteristic declaration
295   EXPECT_EQ(srvc_handle + 1, attrs[1].handle());
296   EXPECT_EQ(types::kCharacteristicDeclaration, attrs[1].type());
297   EXPECT_EQ(AllowedNoSecurity(), attrs[1].read_reqs());
298   EXPECT_EQ(att::AccessRequirements(), attrs[1].write_reqs());
299   EXPECT_TRUE(attrs[1].value());
300 
301   const StaticByteBuffer kDeclValue(0x02,  // properties
302                                     0x03,
303                                     0x00,  // value handle
304 
305                                     // 128-bit UUID
306                                     0xFF,
307                                     0xEE,
308                                     0xDD,
309                                     0xCC,
310                                     0xBB,
311                                     0xAA,
312                                     0x99,
313                                     0x88,
314                                     0x77,
315                                     0x66,
316                                     0x55,
317                                     0x44,
318                                     0x33,
319                                     0x22,
320                                     0x11,
321                                     0x00);
322   EXPECT_TRUE(ContainersEqual(kDeclValue, *attrs[1].value()));
323 
324   // Characteristic value
325   EXPECT_EQ(srvc_handle + 2, attrs[2].handle());
326   EXPECT_EQ(kTestChrcType, attrs[2].type());
327   EXPECT_EQ(kReadReqs, attrs[2].read_reqs());
328   EXPECT_EQ(kWriteReqs, attrs[2].write_reqs());
329 
330   // This value is dynamic.
331   EXPECT_FALSE(attrs[2].value());
332 }
333 
TEST(LocalServiceManagerTest,ExtPropSetSuccess)334 TEST(LocalServiceManagerTest, ExtPropSetSuccess) {
335   LocalServiceManager mgr;
336   const att::AccessRequirements kReadReqs, kWriteReqs, kUpdateReqs;
337   constexpr UUID kChrcType16(uint16_t{0x1234});
338   constexpr IdType kChrcId = 5;
339 
340   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
341 
342   constexpr uint8_t kChrcProps = Property::kRead;
343   constexpr uint8_t kExtChrcProps = ExtendedProperty::kReliableWrite;
344   auto chrc = std::make_unique<Characteristic>(kChrcId,
345                                                kChrcType16,
346                                                kChrcProps,
347                                                kExtChrcProps,
348                                                kReadReqs,
349                                                kWriteReqs,
350                                                kUpdateReqs);
351   service->AddCharacteristic(std::move(chrc));
352 
353   ASSERT_TRUE(RegisterService(&mgr, std::move(service)));
354   ASSERT_NE(0u, mgr.database()->groupings().size());
355   const auto& grouping = mgr.database()->groupings().front();
356   const auto& attrs = grouping.attributes();
357   ASSERT_EQ(4u, attrs.size());
358   EXPECT_EQ(types::kCharacteristicExtProperties, attrs[3].type());
359   EXPECT_TRUE(ContainersEqual(  // Reliable Write property
360       StaticByteBuffer(0x01, 0x00),
361       *attrs[3].value()));
362 }
363 
364 // tests that the extended properties descriptor cannot be set externally
TEST(LocalServiceManagerTest,ExtPropSetFailure)365 TEST(LocalServiceManagerTest, ExtPropSetFailure) {
366   LocalServiceManager mgr;
367   const att::AccessRequirements kReadReqs, kWriteReqs, kUpdateReqs;
368 
369   constexpr UUID kChrcType16(uint16_t{0x1234});
370   constexpr UUID kDescType16(uint16_t{0x2900});  // UUID for Ext Prop
371 
372   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
373   auto chrc = std::make_unique<Characteristic>(
374       0, kChrcType16, 0, 0, kReadReqs, kWriteReqs, kUpdateReqs);
375   chrc->AddDescriptor(
376       std::make_unique<Descriptor>(1, kDescType16, kReadReqs, kWriteReqs));
377   service->AddCharacteristic(std::move(chrc));
378 
379   EXPECT_EQ(false, RegisterService(&mgr, std::move(service)));
380 }
381 
TEST(LocalServiceManagerTest,RegisterCharacteristicSorted)382 TEST(LocalServiceManagerTest, RegisterCharacteristicSorted) {
383   LocalServiceManager mgr;
384   const att::AccessRequirements kReadReqs, kWriteReqs, kUpdateReqs;
385 
386   constexpr UUID kType16(uint16_t{0xbeef});
387   constexpr UUID kType128(uint32_t{0xdeadbeef});
388 
389   constexpr IdType kChrcId0 = 0;
390   constexpr uint8_t kChrcProps0 = 0;
391   constexpr IdType kChrcId1 = 1;
392   constexpr uint8_t kChrcProps1 = 1;
393   constexpr IdType kChrcId2 = 2;
394   constexpr uint8_t kChrcProps2 = 2;
395   constexpr IdType kChrcId3 = 3;
396   constexpr uint8_t kChrcProps3 = 3;
397 
398   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
399   service->AddCharacteristic(std::make_unique<Characteristic>(
400       kChrcId0, kType128, kChrcProps0, 0, kReadReqs, kWriteReqs, kUpdateReqs));
401   service->AddCharacteristic(std::make_unique<Characteristic>(
402       kChrcId1, kType16, kChrcProps1, 0, kReadReqs, kWriteReqs, kUpdateReqs));
403   service->AddCharacteristic(std::make_unique<Characteristic>(
404       kChrcId2, kType128, kChrcProps2, 0, kReadReqs, kWriteReqs, kUpdateReqs));
405   service->AddCharacteristic(std::make_unique<Characteristic>(
406       kChrcId3, kType16, kChrcProps3, 0, kReadReqs, kWriteReqs, kUpdateReqs));
407   auto id1 = RegisterService(&mgr, std::move(service));
408   EXPECT_NE(0u, id1);
409 
410   ASSERT_EQ(1u, mgr.database()->groupings().size());
411   const auto& grouping = mgr.database()->groupings().front();
412   EXPECT_TRUE(grouping.complete());
413 
414   const auto& attrs = grouping.attributes();
415   ASSERT_EQ(9u, attrs.size());
416 
417   // The declaration attributes should be sorted by service type (16-bit UUIDs
418   // first).
419   ASSERT_TRUE(attrs[1].value());
420   EXPECT_EQ(kChrcProps1, (*attrs[1].value())[0]);
421   ASSERT_TRUE(attrs[3].value());
422   EXPECT_EQ(kChrcProps3, (*attrs[3].value())[0]);
423   ASSERT_TRUE(attrs[5].value());
424   EXPECT_EQ(kChrcProps0, (*attrs[5].value())[0]);
425   ASSERT_TRUE(attrs[7].value());
426   EXPECT_EQ(kChrcProps2, (*attrs[7].value())[0]);
427 }
428 
TEST(LocalServiceManagerTest,RegisterDescriptor)429 TEST(LocalServiceManagerTest, RegisterDescriptor) {
430   LocalServiceManager mgr;
431   const att::AccessRequirements kReadReqs, kWriteReqs, kUpdateReqs;
432 
433   constexpr UUID kChrcType16(uint16_t{0x1234});
434   constexpr UUID kDescType16(uint16_t{0x5678});
435 
436   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
437   auto chrc = std::make_unique<Characteristic>(
438       0, kChrcType16, 0, 0, kReadReqs, kWriteReqs, kUpdateReqs);
439   chrc->AddDescriptor(
440       std::make_unique<Descriptor>(1, kDescType16, kReadReqs, kWriteReqs));
441   service->AddCharacteristic(std::move(chrc));
442 
443   EXPECT_NE(0u, RegisterService(&mgr, std::move(service)));
444   ASSERT_EQ(1u, mgr.database()->groupings().size());
445   const auto& grouping = mgr.database()->groupings().front();
446   EXPECT_TRUE(grouping.complete());
447 
448   const auto& attrs = grouping.attributes();
449   ASSERT_EQ(4u, attrs.size());
450   EXPECT_EQ(types::kCharacteristicDeclaration, attrs[1].type());
451   EXPECT_EQ(kChrcType16, attrs[2].type());
452   EXPECT_EQ(kDescType16, attrs[3].type());
453   EXPECT_FALSE(attrs[3].value());
454 }
455 
TEST(LocalServiceManagerTest,DuplicateChrcIds)456 TEST(LocalServiceManagerTest, DuplicateChrcIds) {
457   LocalServiceManager mgr;
458   const att::AccessRequirements kReadReqs, kWriteReqs, kUpdateReqs;
459 
460   constexpr UUID kChrcType16(uint16_t{0x1234});
461 
462   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
463 
464   // Use same characteristic ID twice.
465   service->AddCharacteristic(std::make_unique<Characteristic>(
466       0, kChrcType16, 0, 0, kReadReqs, kWriteReqs, kUpdateReqs));
467   service->AddCharacteristic(std::make_unique<Characteristic>(
468       0, kChrcType16, 0, 0, kReadReqs, kWriteReqs, kUpdateReqs));
469 
470   EXPECT_EQ(0u, RegisterService(&mgr, std::move(service)));
471 }
472 
TEST(LocalServiceManagerTest,DuplicateDescIds)473 TEST(LocalServiceManagerTest, DuplicateDescIds) {
474   LocalServiceManager mgr;
475   const att::AccessRequirements kReadReqs, kWriteReqs, kUpdateReqs;
476 
477   constexpr UUID kChrcType16(uint16_t{0x1234});
478   constexpr UUID kDescType16(uint16_t{0x5678});
479 
480   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
481 
482   // Use same descriptor ID twice.
483   auto chrc = std::make_unique<Characteristic>(
484       0, kChrcType16, 0, 0, kReadReqs, kWriteReqs, kUpdateReqs);
485   chrc->AddDescriptor(
486       std::make_unique<Descriptor>(1, kDescType16, kReadReqs, kWriteReqs));
487   chrc->AddDescriptor(
488       std::make_unique<Descriptor>(1, kDescType16, kReadReqs, kWriteReqs));
489   service->AddCharacteristic(std::move(chrc));
490 
491   EXPECT_EQ(0u, RegisterService(&mgr, std::move(service)));
492 }
493 
TEST(LocalServiceManagerTest,DuplicateChrcAndDescIds)494 TEST(LocalServiceManagerTest, DuplicateChrcAndDescIds) {
495   LocalServiceManager mgr;
496   const att::AccessRequirements kReadReqs, kWriteReqs, kUpdateReqs;
497 
498   constexpr UUID kChrcType16(uint16_t{0x1234});
499   constexpr UUID kDescType16(uint16_t{0x5678});
500 
501   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
502 
503   // Use same descriptor ID twice.
504   auto chrc = std::make_unique<Characteristic>(
505       0, kChrcType16, 0, 0, kReadReqs, kWriteReqs, kUpdateReqs);
506   chrc->AddDescriptor(
507       std::make_unique<Descriptor>(0, kDescType16, kReadReqs, kWriteReqs));
508   service->AddCharacteristic(std::move(chrc));
509 
510   EXPECT_EQ(0u, RegisterService(&mgr, std::move(service)));
511 }
512 
TEST(LocalServiceManagerTest,ReadCharacteristicNoReadPermission)513 TEST(LocalServiceManagerTest, ReadCharacteristicNoReadPermission) {
514   LocalServiceManager mgr;
515   const att::AccessRequirements kReadReqs, kWriteReqs, kUpdateReqs;
516   constexpr UUID kChrcType16(uint16_t{0x1234});
517   constexpr IdType kChrcId = 5;
518 
519   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
520   service->AddCharacteristic(std::make_unique<Characteristic>(kChrcId,
521                                                               kChrcType16,
522                                                               Property::kRead,
523                                                               0,
524                                                               kReadReqs,
525                                                               kWriteReqs,
526                                                               kUpdateReqs));
527 
528   bool called = false;
529   auto read_cb = [&called](auto, auto, auto, auto, auto) { called = true; };
530 
531   EXPECT_NE(0u, RegisterService(&mgr, std::move(service), std::move(read_cb)));
532 
533   auto* attr = mgr.database()->FindAttribute(kFirstChrcValueHandle);
534   ASSERT_TRUE(attr);
535   EXPECT_EQ(kChrcType16, attr->type());
536 
537   bool result_called = false;
538   auto result_cb = [&result_called](auto, const auto&) {
539     result_called = true;
540   };
541 
542   EXPECT_FALSE(attr->ReadAsync(kTestPeerId, 0, std::move(result_cb)));
543   EXPECT_FALSE(called);
544   EXPECT_FALSE(result_called);
545 }
546 
TEST(LocalServiceManagerTest,ReadCharacteristicNoReadProperty)547 TEST(LocalServiceManagerTest, ReadCharacteristicNoReadProperty) {
548   LocalServiceManager mgr;
549   constexpr UUID kChrcType16(uint16_t{0x1234});
550   constexpr IdType kChrcId = 5;
551 
552   // Characteristic is readable but doesn't have the "read" property.
553   auto kReadReqs = AllowedNoSecurity();
554   const att::AccessRequirements kWriteReqs, kUpdateReqs;
555 
556   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
557   service->AddCharacteristic(std::make_unique<Characteristic>(
558       kChrcId, kChrcType16, 0, 0, kReadReqs, kWriteReqs, kUpdateReqs));
559 
560   bool called = false;
561   auto read_cb = [&called](auto, auto, auto, auto, auto) { called = true; };
562 
563   EXPECT_NE(0u, RegisterService(&mgr, std::move(service), std::move(read_cb)));
564 
565   auto* attr = mgr.database()->FindAttribute(kFirstChrcValueHandle);
566   ASSERT_TRUE(attr);
567   EXPECT_EQ(kChrcType16, attr->type());
568 
569   fit::result<att::ErrorCode> status = fit::ok();
570   auto result_cb = [&status](auto cb_status, const auto&) {
571     status = cb_status;
572   };
573 
574   EXPECT_TRUE(attr->ReadAsync(kTestPeerId, 0, std::move(result_cb)));
575 
576   // The error should be handled internally and not reach |read_cb|.
577   EXPECT_FALSE(called);
578   ASSERT_TRUE(status.is_error());
579   EXPECT_EQ(att::ErrorCode::kReadNotPermitted, status.error_value());
580 }
581 
TEST(LocalServiceManagerTest,ReadCharacteristic)582 TEST(LocalServiceManagerTest, ReadCharacteristic) {
583   LocalServiceManager mgr;
584   constexpr UUID kChrcType16(uint16_t{0x1234});
585   constexpr IdType kChrcId = 5;
586   constexpr uint16_t kOffset = 10;
587 
588   const StaticByteBuffer kTestValue('f', 'o', 'o');
589 
590   auto kReadReqs = AllowedNoSecurity();
591   const att::AccessRequirements kWriteReqs, kUpdateReqs;
592 
593   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
594   service->AddCharacteristic(std::make_unique<Characteristic>(kChrcId,
595                                                               kChrcType16,
596                                                               Property::kRead,
597                                                               0,
598                                                               kReadReqs,
599                                                               kWriteReqs,
600                                                               kUpdateReqs));
601 
602   bool called = false;
603   IdType svc_id;
604   auto read_cb = [&](PeerId peer_id,
605                      auto cb_svc_id,
606                      auto id,
607                      auto offset,
608                      auto responder) {
609     called = true;
610     EXPECT_EQ(kTestPeerId, peer_id);
611     EXPECT_EQ(svc_id, cb_svc_id);
612     EXPECT_EQ(kChrcId, id);
613     EXPECT_EQ(kOffset, offset);
614     responder(fit::ok(), kTestValue);
615   };
616 
617   svc_id = RegisterService(&mgr, std::move(service), std::move(read_cb));
618   ASSERT_NE(0u, svc_id);
619 
620   auto* attr = mgr.database()->FindAttribute(kFirstChrcValueHandle);
621   ASSERT_TRUE(attr);
622   EXPECT_EQ(kChrcType16, attr->type());
623 
624   fit::result<att::ErrorCode> status =
625       fit::error(att::ErrorCode::kUnlikelyError);
626   auto result_cb = [&status, &kTestValue](auto cb_status, const auto& value) {
627     status = cb_status;
628     EXPECT_TRUE(ContainersEqual(kTestValue, value));
629   };
630 
631   EXPECT_TRUE(attr->ReadAsync(kTestPeerId, kOffset, std::move(result_cb)));
632 
633   EXPECT_TRUE(called);
634   EXPECT_EQ(fit::ok(), status);
635 }
636 
TEST(LocalServiceManagerTest,WriteCharacteristicNoWritePermission)637 TEST(LocalServiceManagerTest, WriteCharacteristicNoWritePermission) {
638   LocalServiceManager mgr;
639   const att::AccessRequirements kReadReqs, kWriteReqs, kUpdateReqs;
640   constexpr UUID kChrcType16(uint16_t{0x1234});
641   constexpr IdType kChrcId = 5;
642   const BufferView kTestValue;
643 
644   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
645   service->AddCharacteristic(std::make_unique<Characteristic>(kChrcId,
646                                                               kChrcType16,
647                                                               Property::kWrite,
648                                                               0,
649                                                               kReadReqs,
650                                                               kWriteReqs,
651                                                               kUpdateReqs));
652 
653   bool called = false;
654   auto write_cb = [&called](auto, auto, auto, auto, auto&, auto) {
655     called = true;
656   };
657 
658   EXPECT_NE(0u,
659             RegisterService(
660                 &mgr, std::move(service), NopReadHandler, std::move(write_cb)));
661 
662   auto* attr = mgr.database()->FindAttribute(kFirstChrcValueHandle);
663   ASSERT_TRUE(attr);
664   EXPECT_EQ(kChrcType16, attr->type());
665 
666   bool result_called = false;
667   auto result_cb = [&result_called](auto) { result_called = true; };
668 
669   EXPECT_FALSE(
670       attr->WriteAsync(kTestPeerId, 0, kTestValue, std::move(result_cb)));
671   EXPECT_FALSE(called);
672   EXPECT_FALSE(result_called);
673 }
674 
TEST(LocalServiceManagerTest,WriteCharacteristicNoWriteProperty)675 TEST(LocalServiceManagerTest, WriteCharacteristicNoWriteProperty) {
676   LocalServiceManager mgr;
677   constexpr UUID kChrcType16(uint16_t{0x1234});
678   constexpr IdType kChrcId = 5;
679   const BufferView kTestValue;
680 
681   const att::AccessRequirements kReadReqs, kUpdateReqs;
682   auto kWriteReqs = AllowedNoSecurity();
683 
684   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
685   service->AddCharacteristic(std::make_unique<Characteristic>(
686       kChrcId, kChrcType16, 0, 0, kReadReqs, kWriteReqs, kUpdateReqs));
687 
688   bool called = false;
689   auto write_cb = [&called](auto, auto, auto, auto, auto&, auto) {
690     called = true;
691   };
692 
693   EXPECT_NE(0u,
694             RegisterService(
695                 &mgr, std::move(service), NopReadHandler, std::move(write_cb)));
696 
697   auto* attr = mgr.database()->FindAttribute(kFirstChrcValueHandle);
698   ASSERT_TRUE(attr);
699   EXPECT_EQ(kChrcType16, attr->type());
700 
701   fit::result<att::ErrorCode> status = fit::ok();
702   auto result_cb = [&status](auto cb_status) { status = cb_status; };
703 
704   EXPECT_TRUE(
705       attr->WriteAsync(kTestPeerId, 0, kTestValue, std::move(result_cb)));
706 
707   // The error should be handled internally and not reach |write_cb|.
708   EXPECT_FALSE(called);
709   ASSERT_TRUE(status.is_error());
710   EXPECT_EQ(att::ErrorCode::kWriteNotPermitted, status.error_value());
711 }
712 
TEST(LocalServiceManagerTest,WriteCharacteristic)713 TEST(LocalServiceManagerTest, WriteCharacteristic) {
714   LocalServiceManager mgr;
715   constexpr UUID kChrcType16(uint16_t{0x1234});
716   constexpr IdType kChrcId = 5;
717   constexpr uint16_t kOffset = 10;
718 
719   const StaticByteBuffer kTestValue('f', 'o', 'o');
720 
721   const att::AccessRequirements kReadReqs, kUpdateReqs;
722   auto kWriteReqs = AllowedNoSecurity();
723 
724   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
725   service->AddCharacteristic(std::make_unique<Characteristic>(kChrcId,
726                                                               kChrcType16,
727                                                               Property::kWrite,
728                                                               0,
729                                                               kReadReqs,
730                                                               kWriteReqs,
731                                                               kUpdateReqs));
732 
733   bool called = false;
734   IdType svc_id;
735   auto write_cb = [&](PeerId peer_id,
736                       auto cb_svc_id,
737                       auto id,
738                       auto offset,
739                       const auto& value,
740                       auto responder) {
741     called = true;
742     EXPECT_EQ(kTestPeerId, peer_id);
743     EXPECT_EQ(svc_id, cb_svc_id);
744     EXPECT_EQ(kChrcId, id);
745     EXPECT_EQ(kOffset, offset);
746     EXPECT_TRUE(ContainersEqual(kTestValue, value));
747     responder(fit::ok());
748   };
749 
750   svc_id = RegisterService(
751       &mgr, std::move(service), NopReadHandler, std::move(write_cb));
752   ASSERT_NE(0u, svc_id);
753 
754   auto* attr = mgr.database()->FindAttribute(kFirstChrcValueHandle);
755   ASSERT_TRUE(attr);
756   EXPECT_EQ(kChrcType16, attr->type());
757 
758   fit::result<att::ErrorCode> status =
759       fit::error(att::ErrorCode::kUnlikelyError);
760   auto result_cb = [&status](auto cb_status) { status = cb_status; };
761 
762   EXPECT_TRUE(
763       attr->WriteAsync(kTestPeerId, kOffset, kTestValue, std::move(result_cb)));
764 
765   EXPECT_TRUE(called);
766   EXPECT_EQ(fit::ok(), status);
767 }
768 
TEST(LocalServiceManagerTest,ReadDescriptorNoReadPermission)769 TEST(LocalServiceManagerTest, ReadDescriptorNoReadPermission) {
770   LocalServiceManager mgr;
771   const att::AccessRequirements kReadReqs, kWriteReqs, kUpdateReqs;
772   constexpr UUID kChrcType16(uint16_t{0x1234});
773   constexpr UUID kDescType16(uint16_t{0x5678});
774   constexpr IdType kChrcId = 0;
775   constexpr IdType kDescId = 1;
776 
777   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
778   auto chrc = std::make_unique<Characteristic>(
779       kChrcId, kChrcType16, 0, 0, kReadReqs, kWriteReqs, kUpdateReqs);
780   chrc->AddDescriptor(std::make_unique<Descriptor>(
781       kDescId, kDescType16, kReadReqs, kWriteReqs));
782   service->AddCharacteristic(std::move(chrc));
783 
784   bool called = false;
785   auto read_cb = [&called](auto, auto, auto, auto, auto) { called = true; };
786 
787   EXPECT_NE(0u, RegisterService(&mgr, std::move(service), std::move(read_cb)));
788 
789   auto* attr = mgr.database()->FindAttribute(kFirstDescrHandle);
790   ASSERT_TRUE(attr);
791   EXPECT_EQ(kDescType16, attr->type());
792 
793   bool result_called = false;
794   auto result_cb = [&result_called](auto, const auto&) {
795     result_called = true;
796   };
797 
798   EXPECT_FALSE(attr->ReadAsync(kTestPeerId, 0, std::move(result_cb)));
799   EXPECT_FALSE(called);
800   EXPECT_FALSE(result_called);
801 }
802 
TEST(LocalServiceManagerTest,ReadDescriptor)803 TEST(LocalServiceManagerTest, ReadDescriptor) {
804   LocalServiceManager mgr;
805   constexpr UUID kChrcType16(uint16_t{0x1234});
806   constexpr UUID kDescType16(uint16_t{0x5678});
807   constexpr IdType kChrcId = 0;
808   constexpr IdType kDescId = 1;
809   constexpr uint16_t kOffset = 10;
810 
811   const StaticByteBuffer kTestValue('f', 'o', 'o');
812 
813   auto kReadReqs = AllowedNoSecurity();
814   const att::AccessRequirements kWriteReqs, kUpdateReqs;
815 
816   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
817   auto chrc = std::make_unique<Characteristic>(
818       kChrcId, kChrcType16, 0, 0, kReadReqs, kWriteReqs, kUpdateReqs);
819   chrc->AddDescriptor(
820       std::make_unique<Descriptor>(kDescId, kDescType16, kReadReqs, kReadReqs));
821   service->AddCharacteristic(std::move(chrc));
822 
823   bool called = false;
824   IdType svc_id;
825   auto read_cb = [&](PeerId peer_id,
826                      auto cb_svc_id,
827                      auto id,
828                      auto offset,
829                      auto responder) {
830     called = true;
831     EXPECT_EQ(kTestPeerId, peer_id);
832     EXPECT_EQ(svc_id, cb_svc_id);
833     EXPECT_EQ(kDescId, id);
834     EXPECT_EQ(kOffset, offset);
835     responder(fit::ok(), kTestValue);
836   };
837 
838   svc_id = RegisterService(&mgr, std::move(service), std::move(read_cb));
839   ASSERT_NE(0u, svc_id);
840 
841   auto* attr = mgr.database()->FindAttribute(kFirstDescrHandle);
842   ASSERT_TRUE(attr);
843   EXPECT_EQ(kDescType16, attr->type());
844 
845   fit::result<att::ErrorCode> status =
846       fit::error(att::ErrorCode::kUnlikelyError);
847   auto result_cb = [&status, &kTestValue](auto cb_status, const auto& value) {
848     status = cb_status;
849     EXPECT_TRUE(ContainersEqual(kTestValue, value));
850   };
851 
852   EXPECT_TRUE(attr->ReadAsync(kTestPeerId, kOffset, std::move(result_cb)));
853 
854   EXPECT_TRUE(called);
855   EXPECT_EQ(fit::ok(), status);
856 }
857 
TEST(LocalServiceManagerTest,WriteDescriptorNoWritePermission)858 TEST(LocalServiceManagerTest, WriteDescriptorNoWritePermission) {
859   LocalServiceManager mgr;
860   const att::AccessRequirements kReadReqs, kWriteReqs, kUpdateReqs;
861   constexpr UUID kChrcType16(uint16_t{0x1234});
862   constexpr UUID kDescType16(uint16_t{0x5678});
863   constexpr IdType kChrcId = 0;
864   constexpr IdType kDescId = 1;
865   const BufferView kTestValue;
866 
867   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
868   auto chrc = std::make_unique<Characteristic>(
869       kChrcId, kChrcType16, 0, 0, kReadReqs, kWriteReqs, kUpdateReqs);
870   chrc->AddDescriptor(std::make_unique<Descriptor>(
871       kDescId, kDescType16, kReadReqs, kWriteReqs));
872   service->AddCharacteristic(std::move(chrc));
873 
874   bool called = false;
875   auto write_cb = [&called](auto, auto, auto, auto, auto&, auto) {
876     called = true;
877   };
878 
879   EXPECT_NE(
880       0u, RegisterService(&mgr, std::move(service), NopReadHandler, write_cb));
881 
882   auto* attr = mgr.database()->FindAttribute(kFirstDescrHandle);
883   ASSERT_TRUE(attr);
884   EXPECT_EQ(kDescType16, attr->type());
885 
886   bool result_called = false;
887   auto result_cb = [&result_called](auto) { result_called = true; };
888 
889   EXPECT_FALSE(attr->WriteAsync(kTestPeerId, 0, kTestValue, result_cb));
890   EXPECT_FALSE(called);
891   EXPECT_FALSE(result_called);
892 }
893 
TEST(LocalServiceManagerTest,WriteDescriptor)894 TEST(LocalServiceManagerTest, WriteDescriptor) {
895   LocalServiceManager mgr;
896   constexpr UUID kChrcType16(uint16_t{0x1234});
897   constexpr UUID kDescType16(uint16_t{0x5678});
898   constexpr IdType kChrcId = 0;
899   constexpr IdType kDescId = 1;
900   constexpr uint16_t kOffset = 10;
901 
902   const StaticByteBuffer kTestValue('f', 'o', 'o');
903 
904   const att::AccessRequirements kReadReqs, kUpdateReqs;
905   auto kWriteReqs = AllowedNoSecurity();
906 
907   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
908   auto chrc = std::make_unique<Characteristic>(
909       kChrcId, kChrcType16, 0, 0, kReadReqs, kWriteReqs, kUpdateReqs);
910   chrc->AddDescriptor(std::make_unique<Descriptor>(
911       kDescId, kDescType16, kReadReqs, kWriteReqs));
912   service->AddCharacteristic(std::move(chrc));
913 
914   bool called = false;
915   IdType svc_id;
916   auto write_cb = [&](PeerId peer_id,
917                       auto cb_svc_id,
918                       auto id,
919                       auto offset,
920                       const auto& value,
921                       auto responder) {
922     called = true;
923     EXPECT_EQ(kTestPeerId, peer_id);
924     EXPECT_EQ(svc_id, cb_svc_id);
925     EXPECT_EQ(kDescId, id);
926     EXPECT_EQ(kOffset, offset);
927     EXPECT_TRUE(ContainersEqual(kTestValue, value));
928     responder(fit::ok());
929   };
930 
931   svc_id = RegisterService(&mgr, std::move(service), NopReadHandler, write_cb);
932   ASSERT_NE(0u, svc_id);
933 
934   auto* attr = mgr.database()->FindAttribute(kFirstDescrHandle);
935   ASSERT_TRUE(attr);
936   EXPECT_EQ(kDescType16, attr->type());
937 
938   fit::result<att::ErrorCode> status =
939       fit::error(att::ErrorCode::kUnlikelyError);
940   auto result_cb = [&status](auto cb_status) { status = cb_status; };
941 
942   EXPECT_TRUE(attr->WriteAsync(kTestPeerId, kOffset, kTestValue, result_cb));
943 
944   EXPECT_TRUE(called);
945   EXPECT_EQ(fit::ok(), status);
946 }
947 
TEST(LocalServiceManagerTest,ServiceChanged)948 TEST(LocalServiceManagerTest, ServiceChanged) {
949   IdType expected_id;
950   att::Handle expected_start, expected_end;
951   int callback_count = 0;
952   ServiceChangedCallback service_changed_callback =
953       [&](IdType id, att::Handle start, att::Handle end) {
954         callback_count++;
955         EXPECT_EQ(expected_id, id);
956         EXPECT_EQ(expected_start, start);
957         EXPECT_EQ(expected_end, end);
958       };
959 
960   LocalServiceManager mgr;
961 
962   // Other tests add and remove services without the callback so there is
963   // already the expectation that they work.
964   mgr.set_service_changed_callback(std::move(service_changed_callback));
965 
966   expected_id = 1u;
967   expected_start = 1u;
968   expected_end = 1u;
969   auto service = std::make_unique<Service>(/*primary=*/true, kTestType16);
970   auto id1 = RegisterService(&mgr, std::move(service));
971   EXPECT_NE(0u, id1);
972   EXPECT_EQ(1, callback_count);
973 
974   expected_start = 2u;
975   expected_end = 2u;
976   service = std::make_unique<Service>(/*primary=*/false, kTestType32);
977 
978   constexpr IdType kChrcId = 0;
979   constexpr uint8_t kChrcProps = Property::kRead;
980   constexpr UUID kTestChrcType(uint32_t{0xdeadbeef});
981   const att::AccessRequirements kReadReqs(/*encryption=*/true,
982                                           /*authentication=*/true,
983                                           /*authorization=*/true);
984   const att::AccessRequirements kWriteReqs, kUpdateReqs;
985   service->AddCharacteristic(std::make_unique<Characteristic>(kChrcId,
986                                                               kTestChrcType,
987                                                               kChrcProps,
988                                                               0,
989                                                               kReadReqs,
990                                                               kWriteReqs,
991                                                               kUpdateReqs));
992   expected_id = 2u;
993   expected_start = 2u;
994   expected_end = 4u;
995   auto id2 = RegisterService(&mgr, std::move(service));
996   EXPECT_NE(0u, id2);
997   EXPECT_EQ(2, callback_count);
998 
999   expected_id = id1;
1000   expected_start = 1u;
1001   expected_end = 1u;
1002   EXPECT_TRUE(mgr.UnregisterService(id1));
1003   EXPECT_EQ(3, callback_count);
1004 
1005   expected_id = id2;
1006   expected_start = 2u;
1007   expected_end = 4u;
1008   EXPECT_TRUE(mgr.UnregisterService(id2));
1009   EXPECT_EQ(4, callback_count);
1010 }
1011 
1012 // TODO(armansito): Some functional groupings of tests above (such as
1013 // ReadCharacteristic, WriteCharacteristic, etc) should each use a common test
1014 // harness to reduce code duplication.
1015 class LocalClientCharacteristicConfigurationTest : public ::testing::Test {
1016  protected:
1017   LocalServiceManager mgr;
1018 
1019   // The CCC descriptor is set up as the first descriptor of the first
1020   // characteristic of the first service:
1021   //   0x0001: service decl.
1022   //   0x0002: characteristic decl.
1023   //   0x0003: characteristic value
1024   //   0x0004: CCC descriptor
1025   const att::Handle kChrcHandle = 0x0003;
1026   const att::Handle kCCCHandle = 0x0004;
1027 
1028   const IdType kChrcId = 0;
1029 
1030   const uint16_t kEnableNot = 0x0001;
1031   const uint16_t kEnableInd = 0x0002;
1032 
1033   int ccc_callback_count = 0;
1034   IdType last_service_id = 0u;
1035   PeerId last_peer_id = PeerId(kInvalidId);
1036   bool last_notify = false;
1037   bool last_indicate = false;
1038 
BuildService(uint8_t props,const att::AccessRequirements & update_reqs)1039   void BuildService(uint8_t props, const att::AccessRequirements& update_reqs) {
1040     const att::AccessRequirements kReqs;
1041     auto service = std::make_unique<Service>(/*is_primary=*/true, kTestType16);
1042     service->AddCharacteristic(std::make_unique<Characteristic>(
1043         kChrcId, kTestType32, props, 0, kReqs, kReqs, update_reqs));
1044     auto ccc_callback = [this](IdType cb_svc_id,
1045                                IdType id,
1046                                PeerId peer_id,
1047                                bool notify,
1048                                bool indicate) {
1049       ccc_callback_count++;
1050       EXPECT_EQ(last_service_id, cb_svc_id);
1051       EXPECT_EQ(kChrcId, id);
1052       last_peer_id = peer_id;
1053       last_notify = notify;
1054       last_indicate = indicate;
1055     };
1056 
1057     const size_t last_service_count = mgr.database()->groupings().size();
1058     last_service_id = mgr.RegisterService(
1059         std::move(service), NopReadHandler, NopWriteHandler, ccc_callback);
1060     EXPECT_NE(0u, last_service_id);
1061     EXPECT_EQ(last_service_count + 1u, mgr.database()->groupings().size());
1062   }
1063 
ReadCcc(const att::Attribute * attr,PeerId peer_id,fit::result<att::ErrorCode> * out_status,uint16_t * out_value)1064   bool ReadCcc(const att::Attribute* attr,
1065                PeerId peer_id,
1066                fit::result<att::ErrorCode>* out_status,
1067                uint16_t* out_value) {
1068     PW_CHECK(attr);
1069     PW_CHECK(out_status);
1070     PW_CHECK(out_value);
1071 
1072     auto result_cb = [&out_status, &out_value](auto cb_status,
1073                                                const auto& value) {
1074       *out_status = cb_status;
1075       EXPECT_EQ(2u, value.size());
1076 
1077       if (value.size() == 2u) {
1078         *out_value = pw::bytes::ConvertOrderFrom(cpp20::endian::little,
1079                                                  value.template To<uint16_t>());
1080       }
1081     };
1082 
1083     return attr->ReadAsync(peer_id, 0u, result_cb);
1084   }
1085 
WriteCcc(const att::Attribute * attr,PeerId peer_id,uint16_t ccc_value,fit::result<att::ErrorCode> * out_status)1086   bool WriteCcc(const att::Attribute* attr,
1087                 PeerId peer_id,
1088                 uint16_t ccc_value,
1089                 fit::result<att::ErrorCode>* out_status) {
1090     PW_CHECK(attr);
1091     PW_CHECK(out_status);
1092 
1093     auto result_cb = [&out_status](auto cb_status) { *out_status = cb_status; };
1094     uint16_t value =
1095         pw::bytes::ConvertOrderTo(cpp20::endian::little, ccc_value);
1096     return attr->WriteAsync(
1097         peer_id, 0u, BufferView(&value, sizeof(value)), result_cb);
1098   }
1099 };
1100 
TEST_F(LocalClientCharacteristicConfigurationTest,UpdatePermissions)1101 TEST_F(LocalClientCharacteristicConfigurationTest, UpdatePermissions) {
1102   // Require authentication. This should have no bearing on reads but it should
1103   // prevent writes.
1104   const att::AccessRequirements kUpdateReqs(/*encryption=*/false,
1105                                             /*authentication=*/true,
1106                                             /*authorization=*/false);
1107   constexpr uint8_t kProps = Property::kNotify;
1108   BuildService(kProps, kUpdateReqs);
1109 
1110   auto* attr = mgr.database()->FindAttribute(kCCCHandle);
1111   ASSERT_TRUE(attr);
1112   EXPECT_EQ(types::kClientCharacteristicConfig, attr->type());
1113 
1114   EXPECT_FALSE(attr->read_reqs().authentication_required());
1115   EXPECT_TRUE(attr->write_reqs().authentication_required());
1116 }
1117 
TEST_F(LocalClientCharacteristicConfigurationTest,IndicationNotSupported)1118 TEST_F(LocalClientCharacteristicConfigurationTest, IndicationNotSupported) {
1119   // No security required to enable notifications.
1120   auto kUpdateReqs = AllowedNoSecurity();
1121   constexpr uint8_t kProps = Property::kNotify;
1122   BuildService(kProps, kUpdateReqs);
1123 
1124   auto* attr = mgr.database()->FindAttribute(kCCCHandle);
1125   ASSERT_TRUE(attr);
1126   EXPECT_EQ(types::kClientCharacteristicConfig, attr->type());
1127 
1128   // Enabling indications should fail as the characteristic only supports
1129   // notifications.
1130   fit::result<att::ErrorCode> status = fit::ok();
1131   EXPECT_TRUE(WriteCcc(attr, kTestPeerId, kEnableInd, &status));
1132   ASSERT_TRUE(status.is_error());
1133   EXPECT_EQ(att::ErrorCode::kWriteNotPermitted, status.error_value());
1134 
1135   uint16_t ccc_value;
1136 
1137   // Notifications and indications for this device should remain disabled.
1138   EXPECT_TRUE(ReadCcc(attr, kTestPeerId, &status, &ccc_value));
1139   EXPECT_EQ(fit::ok(), status);
1140   EXPECT_EQ(0x0000, ccc_value);
1141 }
1142 
TEST_F(LocalClientCharacteristicConfigurationTest,NotificationNotSupported)1143 TEST_F(LocalClientCharacteristicConfigurationTest, NotificationNotSupported) {
1144   // No security.
1145   auto kUpdateReqs = AllowedNoSecurity();
1146   constexpr uint8_t kProps = Property::kIndicate;
1147   BuildService(kProps, kUpdateReqs);
1148 
1149   auto* attr = mgr.database()->FindAttribute(kCCCHandle);
1150   ASSERT_TRUE(attr);
1151   EXPECT_EQ(types::kClientCharacteristicConfig, attr->type());
1152 
1153   // Enabling notifications should fail as the characteristic only supports
1154   // indications.
1155   fit::result<att::ErrorCode> status = fit::ok();
1156   EXPECT_TRUE(WriteCcc(attr, kTestPeerId, kEnableNot, &status));
1157   ASSERT_TRUE(status.is_error());
1158   EXPECT_EQ(att::ErrorCode::kWriteNotPermitted, status.error_value());
1159 
1160   uint16_t ccc_value;
1161 
1162   // Notifications and indications for this device should remain disabled.
1163   EXPECT_TRUE(ReadCcc(attr, kTestPeerId, &status, &ccc_value));
1164   EXPECT_EQ(fit::ok(), status);
1165   EXPECT_EQ(0x0000, ccc_value);
1166 }
1167 
TEST_F(LocalClientCharacteristicConfigurationTest,EnableNotify)1168 TEST_F(LocalClientCharacteristicConfigurationTest, EnableNotify) {
1169   // No security.
1170   auto kUpdateReqs = AllowedNoSecurity();
1171   constexpr uint8_t kProps = Property::kNotify;
1172   BuildService(kProps, kUpdateReqs);
1173 
1174   auto* attr = mgr.database()->FindAttribute(kCCCHandle);
1175   ASSERT_TRUE(attr);
1176   EXPECT_EQ(types::kClientCharacteristicConfig, attr->type());
1177 
1178   LocalServiceManager::ClientCharacteristicConfig config;
1179   EXPECT_FALSE(mgr.GetCharacteristicConfig(
1180       last_service_id, kChrcId, kTestPeerId, &config));
1181 
1182   fit::result<att::ErrorCode> status =
1183       fit::error(att::ErrorCode::kUnlikelyError);
1184   EXPECT_TRUE(WriteCcc(attr, kTestPeerId, kEnableNot, &status));
1185   EXPECT_EQ(fit::ok(), status);
1186 
1187   uint16_t ccc_value;
1188 
1189   // Notifications should be enabled for kTestPeerId.
1190   EXPECT_TRUE(ReadCcc(attr, kTestPeerId, &status, &ccc_value));
1191   EXPECT_EQ(fit::ok(), status);
1192   EXPECT_EQ(kEnableNot, ccc_value);
1193 
1194   EXPECT_TRUE(mgr.GetCharacteristicConfig(
1195       last_service_id, kChrcId, kTestPeerId, &config));
1196   EXPECT_EQ(kChrcHandle, config.handle);
1197   EXPECT_TRUE(config.notify);
1198   EXPECT_FALSE(config.indicate);
1199 
1200   // ..but not for kTestPeerId2.
1201   EXPECT_TRUE(ReadCcc(attr, kTestPeerId2, &status, &ccc_value));
1202   EXPECT_EQ(fit::ok(), status);
1203   EXPECT_EQ(0x0000, ccc_value);
1204 
1205   // A set configurations now exists for |kChrcId| but kTestPeerId2 should
1206   // appear as unsubscribed.
1207   EXPECT_TRUE(mgr.GetCharacteristicConfig(
1208       last_service_id, kChrcId, kTestPeerId2, &config));
1209   EXPECT_EQ(kChrcHandle, config.handle);
1210   EXPECT_FALSE(config.notify);
1211   EXPECT_FALSE(config.indicate);
1212 
1213   // The callback should have been notified.
1214   EXPECT_EQ(1, ccc_callback_count);
1215   EXPECT_EQ(kTestPeerId, last_peer_id);
1216   EXPECT_TRUE(last_notify);
1217   EXPECT_FALSE(last_indicate);
1218 
1219   // Enable notifications again. The write should succeed but the callback
1220   // should not get called as the value will remain unchanged.
1221   EXPECT_TRUE(WriteCcc(attr, kTestPeerId, kEnableNot, &status));
1222   EXPECT_EQ(fit::ok(), status);
1223   EXPECT_EQ(1, ccc_callback_count);
1224 }
1225 
TEST_F(LocalClientCharacteristicConfigurationTest,EnableIndicate)1226 TEST_F(LocalClientCharacteristicConfigurationTest, EnableIndicate) {
1227   // No security.
1228   auto kUpdateReqs = AllowedNoSecurity();
1229   constexpr uint8_t kProps = Property::kIndicate;
1230   BuildService(kProps, kUpdateReqs);
1231 
1232   auto* attr = mgr.database()->FindAttribute(kCCCHandle);
1233   ASSERT_TRUE(attr);
1234   EXPECT_EQ(types::kClientCharacteristicConfig, attr->type());
1235 
1236   fit::result<att::ErrorCode> status =
1237       fit::error(att::ErrorCode::kUnlikelyError);
1238   EXPECT_TRUE(WriteCcc(attr, kTestPeerId, kEnableInd, &status));
1239   EXPECT_EQ(fit::ok(), status);
1240 
1241   uint16_t ccc_value;
1242 
1243   // Indications should be enabled for kTestPeerId.
1244   EXPECT_TRUE(ReadCcc(attr, kTestPeerId, &status, &ccc_value));
1245   EXPECT_EQ(fit::ok(), status);
1246   EXPECT_EQ(kEnableInd, ccc_value);
1247 
1248   LocalServiceManager::ClientCharacteristicConfig config;
1249   EXPECT_TRUE(mgr.GetCharacteristicConfig(
1250       last_service_id, kChrcId, kTestPeerId, &config));
1251   EXPECT_EQ(kChrcHandle, config.handle);
1252   EXPECT_FALSE(config.notify);
1253   EXPECT_TRUE(config.indicate);
1254 
1255   // ..but not for kTestPeerId2.
1256   EXPECT_TRUE(ReadCcc(attr, kTestPeerId2, &status, &ccc_value));
1257   EXPECT_EQ(fit::ok(), status);
1258   EXPECT_EQ(0x0000, ccc_value);
1259 
1260   // A set configurations now exists for |kChrcId| but kTestPeerId2 should
1261   // appear as unsubscribed.
1262   EXPECT_TRUE(mgr.GetCharacteristicConfig(
1263       last_service_id, kChrcId, kTestPeerId2, &config));
1264   EXPECT_EQ(kChrcHandle, config.handle);
1265   EXPECT_FALSE(config.notify);
1266   EXPECT_FALSE(config.indicate);
1267 
1268   // The callback should have been notified.
1269   EXPECT_EQ(1, ccc_callback_count);
1270   EXPECT_EQ(kTestPeerId, last_peer_id);
1271   EXPECT_FALSE(last_notify);
1272   EXPECT_TRUE(last_indicate);
1273 
1274   // Enable indications again. The write should succeed but the callback
1275   // should not get called as the value will remain unchanged.
1276   EXPECT_TRUE(WriteCcc(attr, kTestPeerId, kEnableInd, &status));
1277   EXPECT_EQ(fit::ok(), status);
1278   EXPECT_EQ(1, ccc_callback_count);
1279 }
1280 
TEST_F(LocalClientCharacteristicConfigurationTest,DisconnectCleanup)1281 TEST_F(LocalClientCharacteristicConfigurationTest, DisconnectCleanup) {
1282   // No security.
1283   auto kUpdateReqs = AllowedNoSecurity();
1284   constexpr uint8_t kProps = Property::kNotify;
1285   BuildService(kProps, kUpdateReqs);
1286 
1287   auto* attr = mgr.database()->FindAttribute(kCCCHandle);
1288   ASSERT_TRUE(attr);
1289   EXPECT_EQ(types::kClientCharacteristicConfig, attr->type());
1290 
1291   LocalServiceManager::ClientCharacteristicConfig config;
1292   EXPECT_FALSE(mgr.GetCharacteristicConfig(
1293       last_service_id, kChrcId, kTestPeerId, &config));
1294 
1295   fit::result<att::ErrorCode> status =
1296       fit::error(att::ErrorCode::kUnlikelyError);
1297   EXPECT_TRUE(WriteCcc(attr, kTestPeerId, kEnableNot, &status));
1298   EXPECT_EQ(fit::ok(), status);
1299 
1300   // The callback should have been notified.
1301   EXPECT_EQ(1, ccc_callback_count);
1302   EXPECT_EQ(kTestPeerId, last_peer_id);
1303   EXPECT_TRUE(last_notify);
1304   EXPECT_FALSE(last_indicate);
1305 
1306   mgr.DisconnectClient(kTestPeerId);
1307 
1308   uint16_t ccc_value;
1309   // Reads should succeed but notifications should be disabled.
1310   EXPECT_TRUE(ReadCcc(attr, kTestPeerId, &status, &ccc_value));
1311   EXPECT_EQ(fit::ok(), status);
1312   EXPECT_EQ(0x0000, ccc_value);
1313 
1314   // The callback should not have been called on client disconnect.
1315   EXPECT_EQ(1, ccc_callback_count);
1316   EXPECT_EQ(kTestPeerId, last_peer_id);
1317   EXPECT_TRUE(last_notify);
1318   EXPECT_FALSE(last_indicate);
1319 
1320   mgr.DisconnectClient(kTestPeerId2);
1321 
1322   // The callback should not be called on client disconnect.
1323   EXPECT_EQ(1, ccc_callback_count);
1324   EXPECT_EQ(kTestPeerId, last_peer_id);
1325 }
1326 
1327 }  // namespace
1328 }  // namespace bt::gatt
1329