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