xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/att/attribute_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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/att/attribute.h"
16 
17 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
18 #include "pw_unit_test/framework.h"
19 
20 namespace bt::att {
21 namespace {
22 
23 constexpr PeerId kTestPeerId(1);
24 constexpr Handle kTestHandle = 0x0001;
25 constexpr UUID kTestType1(uint16_t{0x0001});
26 constexpr UUID kTestType2(uint16_t{0x0002});
27 constexpr UUID kTestType3(uint16_t{0x0003});
28 constexpr UUID kTestType4(uint16_t{0x0004});
29 
30 const StaticByteBuffer kTestValue('t', 'e', 's', 't');
31 
TEST(AttributeDeathTest,OverflowingMaxHandleOnAttributeGroupDies)32 TEST(AttributeDeathTest, OverflowingMaxHandleOnAttributeGroupDies) {
33   ASSERT_DEATH_IF_SUPPORTED(
34       {
35         AttributeGrouping A(kTestType1, kHandleMax - 1, size_t{2}, kTestValue);
36       },
37       ".*attr_count.*");
38 }
39 
TEST(AttributeTest,AccessRequirementsDefault)40 TEST(AttributeTest, AccessRequirementsDefault) {
41   AccessRequirements reqs;
42   EXPECT_FALSE(reqs.allowed());
43   EXPECT_FALSE(reqs.encryption_required());
44   EXPECT_FALSE(reqs.authentication_required());
45   EXPECT_FALSE(reqs.authorization_required());
46 }
47 
TEST(AttributeTest,AccessRequirements)48 TEST(AttributeTest, AccessRequirements) {
49   AccessRequirements reqs0(
50       /*encryption=*/true, /*authentication=*/false, /*authorization=*/false);
51   EXPECT_TRUE(reqs0.allowed());
52   EXPECT_TRUE(reqs0.encryption_required());
53   EXPECT_FALSE(reqs0.authentication_required());
54   EXPECT_FALSE(reqs0.authorization_required());
55   EXPECT_EQ(reqs0.min_enc_key_size(), sm::kMaxEncryptionKeySize);
56 
57   AccessRequirements reqs1(/*encryption=*/true,
58                            /*authentication=*/false,
59                            /*authorization=*/false,
60                            8);
61   EXPECT_TRUE(reqs1.allowed());
62   EXPECT_TRUE(reqs1.encryption_required());
63   EXPECT_FALSE(reqs1.authentication_required());
64   EXPECT_FALSE(reqs1.authorization_required());
65   EXPECT_EQ(reqs1.min_enc_key_size(), 8u);
66 
67   AccessRequirements reqs2(
68       /*encryption=*/false, /*authentication=*/true, /*authorization=*/false);
69   EXPECT_TRUE(reqs2.allowed());
70   EXPECT_FALSE(reqs2.encryption_required());
71   EXPECT_TRUE(reqs2.authentication_required());
72   EXPECT_FALSE(reqs2.authorization_required());
73 
74   AccessRequirements reqs3(
75       /*encryption=*/false, /*authentication=*/false, /*authorization=*/true);
76   EXPECT_TRUE(reqs3.allowed());
77   EXPECT_FALSE(reqs3.encryption_required());
78   EXPECT_FALSE(reqs3.authentication_required());
79   EXPECT_TRUE(reqs3.authorization_required());
80 
81   AccessRequirements reqs4(
82       /*encryption=*/false, /*authentication=*/false, /*authorization=*/false);
83   EXPECT_TRUE(reqs4.allowed());
84   EXPECT_FALSE(reqs4.encryption_required());
85   EXPECT_FALSE(reqs4.authentication_required());
86   EXPECT_FALSE(reqs4.authorization_required());
87 }
88 
TEST(AttributeTest,GroupingDeclAttr)89 TEST(AttributeTest, GroupingDeclAttr) {
90   constexpr size_t kAttrCount = 0u;
91 
92   AttributeGrouping group(kTestType1, kTestHandle, kAttrCount, kTestValue);
93 
94   // The grouping consists of just the group declaration and is thus complete.
95   EXPECT_TRUE(group.complete());
96   EXPECT_EQ(kTestType1, group.group_type());
97   EXPECT_EQ(kTestHandle, group.start_handle());
98   EXPECT_EQ(kTestHandle, group.end_handle());
99   EXPECT_EQ(1u, group.attributes().size());
100 
101   // The grouping is already complete.
102   EXPECT_FALSE(group.AddAttribute(
103       kTestType2, AccessRequirements(), AccessRequirements()));
104 
105   const Attribute& decl_attr = group.attributes()[0];
106   EXPECT_EQ(kTestHandle, decl_attr.handle());
107   EXPECT_EQ(kTestType1, decl_attr.type());
108   ASSERT_TRUE(decl_attr.value());
109   EXPECT_TRUE(ContainersEqual(kTestValue, *decl_attr.value()));
110   EXPECT_TRUE(decl_attr.read_reqs().allowed());
111   EXPECT_FALSE(decl_attr.read_reqs().encryption_required());
112   EXPECT_FALSE(decl_attr.read_reqs().authentication_required());
113   EXPECT_FALSE(decl_attr.read_reqs().authorization_required());
114   EXPECT_FALSE(decl_attr.write_reqs().allowed());
115   EXPECT_EQ(&group, &decl_attr.group());
116 }
117 
TEST(AttributeTest,GroupingAddAttribute)118 TEST(AttributeTest, GroupingAddAttribute) {
119   constexpr size_t kAttrCount = 2;
120 
121   AttributeGrouping group(kTestType1, kTestHandle, kAttrCount, kTestValue);
122   EXPECT_FALSE(group.complete());
123   EXPECT_EQ(kTestHandle, group.start_handle());
124   EXPECT_EQ(kTestHandle + kAttrCount, group.end_handle());
125 
126   Attribute* attr = group.AddAttribute(
127       kTestType2, AccessRequirements(), AccessRequirements());
128   ASSERT_TRUE(attr);
129   EXPECT_EQ(kTestType2, attr->type());
130   EXPECT_EQ(kTestHandle + 1, attr->handle());
131   EXPECT_EQ(&group, &attr->group());
132 
133   // The attribute should have no value until assigned.
134   EXPECT_FALSE(attr->value());
135   attr->SetValue(kTestValue);
136   ASSERT_TRUE(attr->value());
137   EXPECT_TRUE(ContainersEqual(kTestValue, *attr->value()));
138 
139   // The group is not complete until |kAttrCount| attributes have been added.
140   EXPECT_FALSE(group.complete());
141   EXPECT_EQ(2u, group.attributes().size());
142 
143   attr = group.AddAttribute(
144       kTestType3, AccessRequirements(), AccessRequirements());
145   ASSERT_TRUE(attr);
146   EXPECT_EQ(kTestType3, attr->type());
147 
148   EXPECT_TRUE(group.complete());
149   EXPECT_EQ(group.end_handle(), attr->handle());
150   EXPECT_EQ(3u, group.attributes().size());
151 
152   EXPECT_FALSE(group.AddAttribute(
153       kTestType4, AccessRequirements(), AccessRequirements()));
154 }
155 
TEST(AttributeTest,ReadAsyncReadNotAllowed)156 TEST(AttributeTest, ReadAsyncReadNotAllowed) {
157   AttributeGrouping group(kTestType1, kTestHandle, 1, kTestValue);
158   Attribute* attr = group.AddAttribute(
159       kTestType2, AccessRequirements(), AccessRequirements());
160   EXPECT_FALSE(attr->ReadAsync(kTestPeerId, 0, [](auto, const auto&) {}));
161 }
162 
TEST(AttributeTest,ReadAsyncReadNoHandler)163 TEST(AttributeTest, ReadAsyncReadNoHandler) {
164   AttributeGrouping group(kTestType1, kTestHandle, 1, kTestValue);
165   Attribute* attr = group.AddAttribute(
166       kTestType2,
167       AccessRequirements(/*encryption=*/false,
168                          /*authentication=*/false,
169                          /*authorization=*/false),  // read (no security)
170       AccessRequirements());                        // write not allowed
171   EXPECT_FALSE(attr->ReadAsync(kTestPeerId, 0, [](auto, const auto&) {}));
172 }
173 
TEST(AttributeTest,ReadAsync)174 TEST(AttributeTest, ReadAsync) {
175   constexpr uint16_t kTestOffset = 5;
176 
177   AttributeGrouping group(kTestType1, kTestHandle, 1, kTestValue);
178   Attribute* attr = group.AddAttribute(
179       kTestType2,
180       AccessRequirements(/*encryption=*/false,
181                          /*authentication=*/false,
182                          /*authorization=*/false),  // read (no security)
183       AccessRequirements());                        // write not allowed
184 
185   bool callback_called = false;
186   auto callback = [&](fit::result<ErrorCode> status, const auto& value) {
187     EXPECT_EQ(fit::ok(), status);
188     EXPECT_TRUE(ContainersEqual(StaticByteBuffer('h', 'i'), value));
189     callback_called = true;
190   };
191 
192   auto handler =
193       [&](PeerId peer_id, Handle handle, uint16_t offset, auto result_cb) {
194         EXPECT_EQ(kTestPeerId, peer_id);
195         EXPECT_EQ(attr->handle(), handle);
196         EXPECT_EQ(kTestOffset, offset);
197         EXPECT_TRUE(result_cb);
198 
199         result_cb(fit::ok(), StaticByteBuffer('h', 'i'));
200       };
201 
202   attr->set_read_handler(handler);
203   EXPECT_TRUE(attr->ReadAsync(kTestPeerId, kTestOffset, callback));
204   EXPECT_TRUE(callback_called);
205 }
206 
TEST(AttributeTest,WriteAsyncWriteNotAllowed)207 TEST(AttributeTest, WriteAsyncWriteNotAllowed) {
208   AttributeGrouping group(kTestType1, kTestHandle, 1, kTestValue);
209   Attribute* attr = group.AddAttribute(
210       kTestType2, AccessRequirements(), AccessRequirements());
211   EXPECT_FALSE(attr->WriteAsync(kTestPeerId, 0, BufferView(), [](auto) {}));
212 }
213 
TEST(AttributeTest,WriteAsyncWriteNoHandler)214 TEST(AttributeTest, WriteAsyncWriteNoHandler) {
215   AttributeGrouping group(kTestType1, kTestHandle, 1, kTestValue);
216   Attribute* attr = group.AddAttribute(
217       kTestType2,
218       AccessRequirements(),  // read not allowed
219       AccessRequirements(/*encryption=*/false,
220                          /*authentication=*/false,
221                          /*authorization=*/false));  // write no security
222   EXPECT_FALSE(attr->WriteAsync(kTestPeerId, 0, BufferView(), [](auto) {}));
223 }
224 
TEST(AttributeTest,WriteAsync)225 TEST(AttributeTest, WriteAsync) {
226   constexpr uint16_t kTestOffset = 5;
227 
228   AttributeGrouping group(kTestType1, kTestHandle, 1, kTestValue);
229   Attribute* attr = group.AddAttribute(
230       kTestType2,
231       AccessRequirements(),  // read not allowed
232       AccessRequirements(/*encryption=*/false,
233                          /*authentication=*/false,
234                          /*authorization=*/false));  // write no security
235 
236   bool callback_called = false;
237   auto callback = [&](fit::result<ErrorCode> status) {
238     EXPECT_EQ(fit::ok(), status);
239     callback_called = true;
240   };
241 
242   auto handler = [&](PeerId peer_id,
243                      Handle handle,
244                      uint16_t offset,
245                      const auto& value,
246                      auto result_cb) {
247     EXPECT_EQ(kTestPeerId, peer_id);
248     EXPECT_EQ(attr->handle(), handle);
249     EXPECT_EQ(kTestOffset, offset);
250     EXPECT_TRUE(ContainersEqual(StaticByteBuffer('h', 'i'), value));
251     EXPECT_TRUE(result_cb);
252 
253     result_cb(fit::ok());
254   };
255 
256   attr->set_write_handler(handler);
257   EXPECT_TRUE(attr->WriteAsync(
258       kTestPeerId, kTestOffset, StaticByteBuffer('h', 'i'), callback));
259   EXPECT_TRUE(callback_called);
260 }
261 
262 }  // namespace
263 }  // namespace bt::att
264