1 use std::{
2     rc::Rc,
3     sync::{Arc, Mutex},
4 };
5 
6 use bluetooth_core::{
7     core::uuid::Uuid,
8     gatt::{
9         self,
10         ffi::AttributeBackingType,
11         ids::{AdvertiserId, AttHandle, ServerId, TransportIndex},
12         mocks::{
13             mock_datastore::{MockDatastore, MockDatastoreEvents},
14             mock_transport::MockAttTransport,
15         },
16         server::{
17             gatt_database::{
18                 AttPermissions, GattCharacteristicWithHandle, GattDescriptorWithHandle,
19                 GattServiceWithHandle, CHARACTERISTIC_UUID, PRIMARY_SERVICE_DECLARATION_UUID,
20             },
21             isolation_manager::IsolationManager,
22             services::{
23                 gap::DEVICE_NAME_UUID,
24                 gatt::{
25                     CLIENT_CHARACTERISTIC_CONFIGURATION_UUID, GATT_SERVICE_UUID,
26                     SERVICE_CHANGE_UUID,
27                 },
28             },
29             GattModule, IndicationError,
30         },
31     },
32     packets::{
33         AttAttributeDataChild, AttBuilder, AttChild, AttErrorCode, AttErrorResponseBuilder,
34         AttFindByTypeValueRequestBuilder, AttFindInformationRequestBuilder,
35         AttFindInformationResponseChild, AttHandleValueConfirmationBuilder,
36         AttHandleValueIndicationBuilder, AttOpcode, AttReadByTypeRequestBuilder,
37         AttReadRequestBuilder, AttReadResponseBuilder, AttWriteRequestBuilder,
38         AttWriteResponseBuilder, GattCharacteristicDeclarationValueView,
39         GattClientCharacteristicConfigurationBuilder, GattServiceChangedBuilder,
40         GattServiceDeclarationValueBuilder, Packet, Serializable, UuidAsAttDataBuilder,
41     },
42     utils::packet::{build_att_data, build_att_view_or_crash},
43 };
44 
45 use tokio::{
46     sync::mpsc::{error::TryRecvError, UnboundedReceiver},
47     task::spawn_local,
48 };
49 use utils::start_test;
50 
51 mod utils;
52 
53 const TCB_IDX: TransportIndex = TransportIndex(1);
54 const SERVER_ID: ServerId = ServerId(2);
55 const ADVERTISER_ID: AdvertiserId = AdvertiserId(3);
56 
57 const ANOTHER_TCB_IDX: TransportIndex = TransportIndex(2);
58 const ANOTHER_SERVER_ID: ServerId = ServerId(3);
59 const ANOTHER_ADVERTISER_ID: AdvertiserId = AdvertiserId(4);
60 
61 const SERVICE_HANDLE: AttHandle = AttHandle(6);
62 const CHARACTERISTIC_HANDLE: AttHandle = AttHandle(8);
63 const DESCRIPTOR_HANDLE: AttHandle = AttHandle(9);
64 
65 const SERVICE_TYPE: Uuid = Uuid::new(0x0102);
66 const CHARACTERISTIC_TYPE: Uuid = Uuid::new(0x0103);
67 const DESCRIPTOR_TYPE: Uuid = Uuid::new(0x0104);
68 
69 const DATA: [u8; 4] = [1, 2, 3, 4];
70 const ANOTHER_DATA: [u8; 4] = [5, 6, 7, 8];
71 
start_gatt_module() -> (gatt::server::GattModule, UnboundedReceiver<(TransportIndex, AttBuilder)>)72 fn start_gatt_module() -> (gatt::server::GattModule, UnboundedReceiver<(TransportIndex, AttBuilder)>)
73 {
74     let (transport, transport_rx) = MockAttTransport::new();
75     let arbiter = IsolationManager::new();
76     let gatt = GattModule::new(Rc::new(transport), Arc::new(Mutex::new(arbiter)));
77 
78     (gatt, transport_rx)
79 }
80 
create_server_and_open_connection( gatt: &mut GattModule, ) -> UnboundedReceiver<MockDatastoreEvents>81 fn create_server_and_open_connection(
82     gatt: &mut GattModule,
83 ) -> UnboundedReceiver<MockDatastoreEvents> {
84     gatt.open_gatt_server(SERVER_ID).unwrap();
85     let (datastore, data_rx) = MockDatastore::new();
86     gatt.register_gatt_service(
87         SERVER_ID,
88         GattServiceWithHandle {
89             handle: SERVICE_HANDLE,
90             type_: SERVICE_TYPE,
91             characteristics: vec![GattCharacteristicWithHandle {
92                 handle: CHARACTERISTIC_HANDLE,
93                 type_: CHARACTERISTIC_TYPE,
94                 permissions: AttPermissions::READABLE
95                     | AttPermissions::WRITABLE_WITH_RESPONSE
96                     | AttPermissions::INDICATE,
97                 descriptors: vec![GattDescriptorWithHandle {
98                     handle: DESCRIPTOR_HANDLE,
99                     type_: DESCRIPTOR_TYPE,
100                     permissions: AttPermissions::READABLE | AttPermissions::WRITABLE_WITH_RESPONSE,
101                 }],
102             }],
103         },
104         datastore,
105     )
106     .unwrap();
107     gatt.get_isolation_manager().associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID);
108     gatt.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)).unwrap();
109     data_rx
110 }
111 
112 #[test]
test_service_read()113 fn test_service_read() {
114     start_test(async move {
115         // arrange
116         let (mut gatt, mut transport_rx) = start_gatt_module();
117 
118         create_server_and_open_connection(&mut gatt);
119 
120         // act
121         gatt.get_bearer(TCB_IDX).unwrap().handle_packet(
122             build_att_view_or_crash(AttReadRequestBuilder {
123                 attribute_handle: SERVICE_HANDLE.into(),
124             })
125             .view(),
126         );
127         let (tcb_idx, resp) = transport_rx.recv().await.unwrap();
128 
129         // assert
130         assert_eq!(tcb_idx, TCB_IDX);
131         assert_eq!(
132             resp.to_vec(),
133             AttBuilder {
134                 opcode: AttOpcode::READ_RESPONSE,
135                 _child_: AttReadResponseBuilder {
136                     value: build_att_data(GattServiceDeclarationValueBuilder {
137                         uuid: SERVICE_TYPE.into()
138                     })
139                 }
140                 .into()
141             }
142             .to_vec()
143         );
144     })
145 }
146 
147 #[test]
test_server_closed_while_connected()148 fn test_server_closed_while_connected() {
149     start_test(async move {
150         // arrange: set up a connection to a closed server
151         let (mut gatt, mut transport_rx) = start_gatt_module();
152 
153         // open a server and connect
154         create_server_and_open_connection(&mut gatt);
155         gatt.close_gatt_server(SERVER_ID).unwrap();
156 
157         // act: read from the closed server
158         gatt.get_bearer(TCB_IDX).unwrap().handle_packet(
159             build_att_view_or_crash(AttReadRequestBuilder {
160                 attribute_handle: SERVICE_HANDLE.into(),
161             })
162             .view(),
163         );
164         let (_, resp) = transport_rx.recv().await.unwrap();
165 
166         // assert that the read failed, but that a response was provided
167         assert_eq!(resp.opcode, AttOpcode::ERROR_RESPONSE);
168         assert_eq!(
169             resp._child_,
170             AttErrorResponseBuilder {
171                 opcode_in_error: AttOpcode::READ_REQUEST,
172                 handle_in_error: SERVICE_HANDLE.into(),
173                 error_code: AttErrorCode::INVALID_HANDLE
174             }
175             .into()
176         )
177     });
178 }
179 
180 #[test]
test_characteristic_read()181 fn test_characteristic_read() {
182     start_test(async move {
183         // arrange
184         let (mut gatt, mut transport_rx) = start_gatt_module();
185 
186         let data = AttAttributeDataChild::RawData(DATA.into());
187 
188         let mut data_rx = create_server_and_open_connection(&mut gatt);
189 
190         // act
191         gatt.get_bearer(TCB_IDX).unwrap().handle_packet(
192             build_att_view_or_crash(AttReadRequestBuilder {
193                 attribute_handle: CHARACTERISTIC_HANDLE.into(),
194             })
195             .view(),
196         );
197         let tx = if let MockDatastoreEvents::Read(
198             TCB_IDX,
199             CHARACTERISTIC_HANDLE,
200             AttributeBackingType::Characteristic,
201             tx,
202         ) = data_rx.recv().await.unwrap()
203         {
204             tx
205         } else {
206             unreachable!()
207         };
208         tx.send(Ok(DATA.to_vec())).unwrap();
209         let (tcb_idx, resp) = transport_rx.recv().await.unwrap();
210 
211         // assert
212         assert_eq!(tcb_idx, TCB_IDX);
213         assert_eq!(
214             resp,
215             AttBuilder {
216                 opcode: AttOpcode::READ_RESPONSE,
217                 _child_: AttReadResponseBuilder { value: build_att_data(data) }.into()
218             }
219         );
220     })
221 }
222 
223 #[test]
test_characteristic_write()224 fn test_characteristic_write() {
225     start_test(async move {
226         // arrange
227         let (mut gatt, mut transport_rx) = start_gatt_module();
228 
229         let data = AttAttributeDataChild::RawData(DATA.into());
230 
231         let mut data_rx = create_server_and_open_connection(&mut gatt);
232 
233         // act
234         gatt.get_bearer(TCB_IDX).unwrap().handle_packet(
235             build_att_view_or_crash(AttWriteRequestBuilder {
236                 handle: CHARACTERISTIC_HANDLE.into(),
237                 value: build_att_data(data.clone()),
238             })
239             .view(),
240         );
241         let (tx, written_data) = if let MockDatastoreEvents::Write(
242             TCB_IDX,
243             CHARACTERISTIC_HANDLE,
244             AttributeBackingType::Characteristic,
245             written_data,
246             tx,
247         ) = data_rx.recv().await.unwrap()
248         {
249             (tx, written_data)
250         } else {
251             unreachable!()
252         };
253         tx.send(Ok(())).unwrap();
254         let (tcb_idx, resp) = transport_rx.recv().await.unwrap();
255 
256         // assert
257         assert_eq!(tcb_idx, TCB_IDX);
258         assert_eq!(
259             resp,
260             AttBuilder {
261                 opcode: AttOpcode::WRITE_RESPONSE,
262                 _child_: AttWriteResponseBuilder {}.into()
263             }
264         );
265         assert_eq!(data.to_vec().unwrap(), written_data)
266     })
267 }
268 
269 #[test]
test_send_indication()270 fn test_send_indication() {
271     start_test(async move {
272         // arrange
273         let (mut gatt, mut transport_rx) = start_gatt_module();
274 
275         let data = AttAttributeDataChild::RawData(DATA.into());
276 
277         create_server_and_open_connection(&mut gatt);
278 
279         // act
280         let pending_indication = spawn_local(
281             gatt.get_bearer(TCB_IDX).unwrap().send_indication(CHARACTERISTIC_HANDLE, data.clone()),
282         );
283 
284         let (tcb_idx, resp) = transport_rx.recv().await.unwrap();
285 
286         gatt.get_bearer(TCB_IDX)
287             .unwrap()
288             .handle_packet(build_att_view_or_crash(AttHandleValueConfirmationBuilder {}).view());
289 
290         // assert
291         assert!(matches!(pending_indication.await.unwrap(), Ok(())));
292         assert_eq!(tcb_idx, TCB_IDX);
293         assert_eq!(
294             resp,
295             AttBuilder {
296                 opcode: AttOpcode::HANDLE_VALUE_INDICATION,
297                 _child_: AttHandleValueIndicationBuilder {
298                     handle: CHARACTERISTIC_HANDLE.into(),
299                     value: build_att_data(data),
300                 }
301                 .into()
302             }
303         );
304     })
305 }
306 
307 #[test]
test_send_indication_and_disconnect()308 fn test_send_indication_and_disconnect() {
309     start_test(async move {
310         // arrange
311         let (mut gatt, mut transport_rx) = start_gatt_module();
312 
313         create_server_and_open_connection(&mut gatt);
314 
315         // act: send an indication, then disconnect
316         let pending_indication = spawn_local(gatt.get_bearer(TCB_IDX).unwrap().send_indication(
317             CHARACTERISTIC_HANDLE,
318             AttAttributeDataChild::RawData([1, 2, 3, 4].into()),
319         ));
320         transport_rx.recv().await.unwrap();
321         gatt.on_le_disconnect(TCB_IDX).unwrap();
322 
323         // assert: the pending indication resolves appropriately
324         assert!(matches!(
325             pending_indication.await.unwrap(),
326             Err(IndicationError::ConnectionDroppedWhileWaitingForConfirmation)
327         ));
328     })
329 }
330 
331 #[test]
test_write_to_descriptor()332 fn test_write_to_descriptor() {
333     start_test(async move {
334         // arrange
335         let (mut gatt, mut transport_rx) = start_gatt_module();
336 
337         let data = AttAttributeDataChild::RawData(DATA.into());
338 
339         let mut data_rx = create_server_and_open_connection(&mut gatt);
340 
341         // act
342         gatt.get_bearer(TCB_IDX).unwrap().handle_packet(
343             build_att_view_or_crash(AttWriteRequestBuilder {
344                 handle: DESCRIPTOR_HANDLE.into(),
345                 value: build_att_data(data.clone()),
346             })
347             .view(),
348         );
349         let (tx, written_data) = if let MockDatastoreEvents::Write(
350             TCB_IDX,
351             DESCRIPTOR_HANDLE,
352             AttributeBackingType::Descriptor,
353             written_data,
354             tx,
355         ) = data_rx.recv().await.unwrap()
356         {
357             (tx, written_data)
358         } else {
359             unreachable!()
360         };
361         tx.send(Ok(())).unwrap();
362         let (tcb_idx, resp) = transport_rx.recv().await.unwrap();
363 
364         // assert
365         assert_eq!(tcb_idx, TCB_IDX);
366         assert_eq!(
367             resp,
368             AttBuilder {
369                 opcode: AttOpcode::WRITE_RESPONSE,
370                 _child_: AttWriteResponseBuilder {}.into()
371             }
372         );
373         assert_eq!(data.to_vec().unwrap(), written_data)
374     })
375 }
376 
377 #[test]
test_multiple_servers()378 fn test_multiple_servers() {
379     start_test(async move {
380         // arrange
381         let (mut gatt, mut transport_rx) = start_gatt_module();
382         // open the default server (SERVER_ID on CONN_ID)
383         let mut data_rx_1 = create_server_and_open_connection(&mut gatt);
384         // open a second server and connect to it (ANOTHER_SERVER_ID on ANOTHER_CONN_ID)
385         let (datastore, mut data_rx_2) = MockDatastore::new();
386         gatt.open_gatt_server(ANOTHER_SERVER_ID).unwrap();
387         gatt.register_gatt_service(
388             ANOTHER_SERVER_ID,
389             GattServiceWithHandle {
390                 handle: SERVICE_HANDLE,
391                 type_: SERVICE_TYPE,
392                 characteristics: vec![GattCharacteristicWithHandle {
393                     handle: CHARACTERISTIC_HANDLE,
394                     type_: CHARACTERISTIC_TYPE,
395                     permissions: AttPermissions::READABLE,
396                     descriptors: vec![],
397                 }],
398             },
399             datastore,
400         )
401         .unwrap();
402         gatt.get_isolation_manager()
403             .associate_server_with_advertiser(ANOTHER_SERVER_ID, ANOTHER_ADVERTISER_ID);
404         gatt.on_le_connect(ANOTHER_TCB_IDX, Some(ANOTHER_ADVERTISER_ID)).unwrap();
405 
406         // act: read from both connections
407         gatt.get_bearer(TCB_IDX).unwrap().handle_packet(
408             build_att_view_or_crash(AttReadRequestBuilder {
409                 attribute_handle: CHARACTERISTIC_HANDLE.into(),
410             })
411             .view(),
412         );
413         gatt.get_bearer(ANOTHER_TCB_IDX).unwrap().handle_packet(
414             build_att_view_or_crash(AttReadRequestBuilder {
415                 attribute_handle: CHARACTERISTIC_HANDLE.into(),
416             })
417             .view(),
418         );
419         // service the first read with `data`
420         let MockDatastoreEvents::Read(TCB_IDX, _, _, tx) = data_rx_1.recv().await.unwrap() else {
421             unreachable!()
422         };
423         tx.send(Ok(DATA.to_vec())).unwrap();
424         // and then the second read with `another_data`
425         let MockDatastoreEvents::Read(ANOTHER_TCB_IDX, _, _, tx) = data_rx_2.recv().await.unwrap()
426         else {
427             unreachable!()
428         };
429         tx.send(Ok(ANOTHER_DATA.to_vec())).unwrap();
430 
431         // receive both response packets
432         let (tcb_idx_1, resp_1) = transport_rx.recv().await.unwrap();
433         let (tcb_idx_2, resp_2) = transport_rx.recv().await.unwrap();
434 
435         // assert: the responses were routed to the correct connections
436         assert_eq!(tcb_idx_1, TCB_IDX);
437         assert_eq!(resp_1._child_.to_vec().unwrap(), DATA);
438         assert_eq!(tcb_idx_2, ANOTHER_TCB_IDX);
439         assert_eq!(resp_2._child_.to_vec().unwrap(), ANOTHER_DATA);
440     })
441 }
442 
443 #[test]
test_read_device_name()444 fn test_read_device_name() {
445     start_test(async move {
446         // arrange
447         let (mut gatt, mut transport_rx) = start_gatt_module();
448         create_server_and_open_connection(&mut gatt);
449 
450         // act: try to read the device name
451         gatt.get_bearer(TCB_IDX).unwrap().handle_packet(
452             build_att_view_or_crash(AttReadByTypeRequestBuilder {
453                 starting_handle: AttHandle(1).into(),
454                 ending_handle: AttHandle(0xFFFF).into(),
455                 attribute_type: DEVICE_NAME_UUID.into(),
456             })
457             .view(),
458         );
459         let (tcb_idx, resp) = transport_rx.recv().await.unwrap();
460 
461         // assert: the name should not be readable
462         assert_eq!(tcb_idx, TCB_IDX);
463         let AttChild::AttErrorResponse(resp) = resp._child_ else {
464             unreachable!("{resp:?}");
465         };
466         assert_eq!(resp.error_code, AttErrorCode::INSUFFICIENT_AUTHENTICATION);
467     });
468 }
469 
470 #[test]
test_ignored_service_change_indication()471 fn test_ignored_service_change_indication() {
472     start_test(async move {
473         // arrange
474         let (mut gatt, mut transport_rx) = start_gatt_module();
475         create_server_and_open_connection(&mut gatt);
476 
477         // act: add a new service
478         let (datastore, _) = MockDatastore::new();
479         gatt.register_gatt_service(
480             SERVER_ID,
481             GattServiceWithHandle {
482                 handle: AttHandle(30),
483                 type_: SERVICE_TYPE,
484                 characteristics: vec![],
485             },
486             datastore,
487         )
488         .unwrap();
489 
490         // assert: no packets should be sent
491         assert_eq!(transport_rx.try_recv().unwrap_err(), TryRecvError::Empty);
492     });
493 }
494 
495 #[test]
test_service_change_indication()496 fn test_service_change_indication() {
497     start_test(async move {
498         // arrange
499         let (mut gatt, mut transport_rx) = start_gatt_module();
500         create_server_and_open_connection(&mut gatt);
501 
502         // act: discover the GATT server
503         gatt.get_bearer(TCB_IDX).unwrap().handle_packet(
504             build_att_view_or_crash(AttFindByTypeValueRequestBuilder {
505                 starting_handle: AttHandle::MIN.into(),
506                 ending_handle: AttHandle::MAX.into(),
507                 attribute_type: PRIMARY_SERVICE_DECLARATION_UUID.try_into().unwrap(),
508                 attribute_value: build_att_data(UuidAsAttDataBuilder {
509                     uuid: GATT_SERVICE_UUID.into(),
510                 }),
511             })
512             .view(),
513         );
514         let AttChild::AttFindByTypeValueResponse(resp) =
515             transport_rx.recv().await.unwrap().1._child_
516         else {
517             unreachable!()
518         };
519         let (starting_handle, ending_handle) = (
520             resp.handles_info[0].clone().found_attribute_handle,
521             resp.handles_info[0].clone().group_end_handle,
522         );
523         // act: discover the service changed characteristic
524         gatt.get_bearer(TCB_IDX).unwrap().handle_packet(
525             build_att_view_or_crash(AttReadByTypeRequestBuilder {
526                 starting_handle,
527                 ending_handle,
528                 attribute_type: CHARACTERISTIC_UUID.into(),
529             })
530             .view(),
531         );
532         let AttChild::AttReadByTypeResponse(resp) = transport_rx.recv().await.unwrap().1._child_
533         else {
534             unreachable!()
535         };
536         let service_change_char_handle: AttHandle = resp
537             .data
538             .into_vec()
539             .into_iter()
540             .find_map(|characteristic| {
541                 let value = characteristic.value.to_vec().unwrap();
542                 let decl =
543                     GattCharacteristicDeclarationValueView::try_parse_from_buffer(value.as_slice())
544                         .unwrap();
545 
546                 if SERVICE_CHANGE_UUID == decl.get_uuid().try_into().unwrap() {
547                     Some(decl.get_handle().into())
548                 } else {
549                     None
550                 }
551             })
552             .unwrap();
553         // act: find the CCC descriptor for the service changed characteristic
554         gatt.get_bearer(TCB_IDX).unwrap().handle_packet(
555             build_att_view_or_crash(AttFindInformationRequestBuilder {
556                 starting_handle: service_change_char_handle.into(),
557                 ending_handle: AttHandle::MAX.into(),
558             })
559             .view(),
560         );
561         let AttChild::AttFindInformationResponse(resp) =
562             transport_rx.recv().await.unwrap().1._child_
563         else {
564             unreachable!()
565         };
566         let AttFindInformationResponseChild::AttFindInformationShortResponse(resp) = resp._child_
567         else {
568             unreachable!()
569         };
570         let service_change_descriptor_handle = resp
571             .data
572             .into_vec()
573             .into_iter()
574             .find_map(|attr| {
575                 if attr.uuid == CLIENT_CHARACTERISTIC_CONFIGURATION_UUID.try_into().unwrap() {
576                     Some(attr.handle)
577                 } else {
578                     None
579                 }
580             })
581             .unwrap();
582         // act: register for indications on this handle
583         gatt.get_bearer(TCB_IDX).unwrap().handle_packet(
584             build_att_view_or_crash(AttWriteRequestBuilder {
585                 handle: service_change_descriptor_handle,
586                 value: build_att_data(GattClientCharacteristicConfigurationBuilder {
587                     notification: 0,
588                     indication: 1,
589                 }),
590             })
591             .view(),
592         );
593         let AttChild::AttWriteResponse(_) = transport_rx.recv().await.unwrap().1._child_ else {
594             unreachable!()
595         };
596         // act: add a new service
597         let (datastore, _) = MockDatastore::new();
598         gatt.register_gatt_service(
599             SERVER_ID,
600             GattServiceWithHandle {
601                 handle: AttHandle(30),
602                 type_: SERVICE_TYPE,
603                 characteristics: vec![],
604             },
605             datastore,
606         )
607         .unwrap();
608 
609         // assert: we got an indication
610         let AttChild::AttHandleValueIndication(indication) =
611             transport_rx.recv().await.unwrap().1._child_
612         else {
613             unreachable!()
614         };
615         assert_eq!(indication.handle, service_change_char_handle.into());
616         assert_eq!(
617             indication.value,
618             build_att_data(GattServiceChangedBuilder {
619                 start_handle: AttHandle(30).into(),
620                 end_handle: AttHandle(30).into(),
621             })
622         );
623     });
624 }
625 
626 #[test]
test_closing_gatt_server_unisolates_advertiser()627 fn test_closing_gatt_server_unisolates_advertiser() {
628     start_test(async move {
629         // arrange
630         let (mut gatt, _) = start_gatt_module();
631         gatt.open_gatt_server(SERVER_ID).unwrap();
632         gatt.get_isolation_manager().associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID);
633 
634         // act
635         gatt.close_gatt_server(SERVER_ID).unwrap();
636 
637         // assert
638         let is_advertiser_isolated =
639             gatt.get_isolation_manager().is_advertiser_isolated(ADVERTISER_ID);
640         assert!(!is_advertiser_isolated);
641     });
642 }
643 
644 #[test]
test_disconnection_unisolates_connection()645 fn test_disconnection_unisolates_connection() {
646     start_test(async move {
647         // arrange
648         let (mut gatt, _) = start_gatt_module();
649         create_server_and_open_connection(&mut gatt);
650 
651         // act
652         gatt.on_le_disconnect(TCB_IDX).unwrap();
653 
654         // assert
655         let is_connection_isolated = gatt.get_isolation_manager().is_connection_isolated(TCB_IDX);
656         assert!(!is_connection_isolated);
657     });
658 }
659