1 use crate::{
2     gatt::server::att_database::AttDatabase,
3     packets::{
4         AttChild, AttErrorResponseBuilder, AttOpcode, AttWriteRequestView, AttWriteResponseBuilder,
5     },
6 };
7 
handle_write_request<T: AttDatabase>( request: AttWriteRequestView<'_>, db: &T, ) -> AttChild8 pub async fn handle_write_request<T: AttDatabase>(
9     request: AttWriteRequestView<'_>,
10     db: &T,
11 ) -> AttChild {
12     let handle = request.get_handle().into();
13     let value = request.get_value().get_raw_payload().collect::<Vec<_>>();
14     match db.write_attribute(handle, &value).await {
15         Ok(()) => AttWriteResponseBuilder {}.into(),
16         Err(error_code) => AttErrorResponseBuilder {
17             opcode_in_error: AttOpcode::WRITE_REQUEST,
18             handle_in_error: handle.into(),
19             error_code,
20         }
21         .into(),
22     }
23 }
24 
25 #[cfg(test)]
26 mod test {
27     use super::*;
28 
29     use tokio_test::block_on;
30 
31     use crate::{
32         core::uuid::Uuid,
33         gatt::{
34             ids::AttHandle,
35             server::{
36                 att_database::{AttAttribute, AttDatabase},
37                 gatt_database::AttPermissions,
38                 test::test_att_db::TestAttDatabase,
39             },
40         },
41         packets::{
42             AttAttributeDataBuilder, AttAttributeDataChild, AttChild, AttErrorCode,
43             AttErrorResponseBuilder, AttWriteRequestBuilder, AttWriteResponseBuilder,
44         },
45         utils::packet::{build_att_data, build_view_or_crash},
46     };
47 
48     #[test]
test_successful_write()49     fn test_successful_write() {
50         // arrange: db with one writable attribute
51         let db = TestAttDatabase::new(vec![(
52             AttAttribute {
53                 handle: AttHandle(1),
54                 type_: Uuid::new(0x1234),
55                 permissions: AttPermissions::READABLE | AttPermissions::WRITABLE_WITH_RESPONSE,
56             },
57             vec![],
58         )]);
59         let data = vec![1, 2];
60 
61         // act: write to the attribute
62         let att_view = build_view_or_crash(AttWriteRequestBuilder {
63             handle: AttHandle(1).into(),
64             value: AttAttributeDataBuilder {
65                 _child_: AttAttributeDataChild::RawData(data.clone().into_boxed_slice()),
66             },
67         });
68         let resp = block_on(handle_write_request(att_view.view(), &db));
69 
70         // assert: that the write succeeded
71         assert_eq!(resp, AttChild::from(AttWriteResponseBuilder {}));
72         assert_eq!(block_on(db.read_attribute(AttHandle(1))).unwrap(), data);
73     }
74 
75     #[test]
test_failed_write()76     fn test_failed_write() {
77         // arrange: db with no writable attributes
78         let db = TestAttDatabase::new(vec![(
79             AttAttribute {
80                 handle: AttHandle(1),
81                 type_: Uuid::new(0x1234),
82                 permissions: AttPermissions::READABLE,
83             },
84             vec![],
85         )]);
86         // act: write to the attribute
87         let att_view = build_view_or_crash(AttWriteRequestBuilder {
88             handle: AttHandle(1).into(),
89             value: build_att_data(AttAttributeDataChild::RawData([1, 2].into())),
90         });
91         let resp = block_on(handle_write_request(att_view.view(), &db));
92 
93         // assert: that the write failed
94         assert_eq!(
95             resp,
96             AttChild::from(AttErrorResponseBuilder {
97                 opcode_in_error: AttOpcode::WRITE_REQUEST,
98                 handle_in_error: AttHandle(1).into(),
99                 error_code: AttErrorCode::WRITE_NOT_PERMITTED
100             })
101         );
102     }
103 }
104