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