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/gatt.h"
16
17 #include <pw_async/fake_dispatcher_fixture.h>
18
19 #include "pw_bluetooth_sapphire/internal/host/att/att.h"
20 #include "pw_bluetooth_sapphire/internal/host/att/error.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/host_error.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/identifier.h"
23 #include "pw_bluetooth_sapphire/internal/host/gatt/fake_client.h"
24 #include "pw_bluetooth_sapphire/internal/host/gatt/gatt_defs.h"
25 #include "pw_bluetooth_sapphire/internal/host/gatt/local_service_manager.h"
26 #include "pw_bluetooth_sapphire/internal/host/gatt/mock_server.h"
27 #include "pw_bluetooth_sapphire/internal/host/l2cap/fake_channel.h"
28 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
29
30 namespace bt::gatt::internal {
31 namespace {
32 constexpr PeerId kPeerId0(0);
33 constexpr PeerId kPeerId1(1);
34 constexpr PeerId kPeerId(10);
35 constexpr UUID kTestServiceUuid0(uint16_t{0xbeef});
36 constexpr IdType kChrcId{13};
37 constexpr bt::UUID kChrcUuid(uint16_t{113u});
38
39 // Factory function for tests of client-facing behavior that don't care about
40 // the server
CreateMockServer(PeerId peer_id,LocalServiceManager::WeakPtr local_services)41 std::unique_ptr<Server> CreateMockServer(
42 PeerId peer_id, LocalServiceManager::WeakPtr local_services) {
43 return std::make_unique<testing::MockServer>(peer_id,
44 std::move(local_services));
45 }
46
47 class GattTest : public pw::async::test::FakeDispatcherFixture {
48 public:
49 GattTest() = default;
50 ~GattTest() override = default;
51
52 protected:
53 struct ServiceWatcherData {
54 PeerId peer_id;
55 std::vector<att::Handle> removed;
56 ServiceList added;
57 ServiceList modified;
58 };
59
SetUp()60 void SetUp() override {
61 auto client = std::make_unique<testing::FakeClient>(dispatcher());
62 fake_client_weak_ = client->AsFakeWeakPtr();
63 client_ = std::move(client);
64 gatt_ = GATT::Create();
65 }
66
TearDown()67 void TearDown() override {
68 // Clear any previous expectations that are based on the ATT Write Request,
69 // so that write requests sent during RemoteService::ShutDown() are ignored.
70 fake_client()->set_write_request_callback({});
71 gatt_.reset();
72 }
73
74 // Register an arbitrary service with a single characteristic of id |kChrcId|,
75 // e.g. for sending notifications. Returns the internal IdType of the
76 // registered service.
RegisterArbitraryService()77 IdType RegisterArbitraryService() {
78 auto svc = std::make_unique<Service>(/*primary=*/true, kTestServiceUuid0);
79 const att::AccessRequirements kReadPerm,
80 kWritePerm; // Default is not allowed
81 // Allow "update" (i.e. indications / notifications) with no security
82 const att::AccessRequirements kUpdatePerm(/*encryption=*/false,
83 /*authentication=*/false,
84 /*authorization=*/false);
85 auto chrc = std::make_unique<Characteristic>(kChrcId,
86 kChrcUuid,
87 Property::kIndicate,
88 /*extended_properties=*/0,
89 kReadPerm,
90 kWritePerm,
91 kUpdatePerm);
92 svc->AddCharacteristic(std::move(chrc));
93
94 std::optional<IdType> svc_id = std::nullopt;
95 auto id_cb = [&svc_id](IdType received_id) {
96 EXPECT_NE(kInvalidId, received_id);
97 svc_id = received_id;
98 };
99 gatt()->RegisterService(std::move(svc),
100 std::move(id_cb),
101 NopReadHandler,
102 NopWriteHandler,
103 NopCCCallback);
104 RunUntilIdle();
105 EXPECT_TRUE(svc_id.has_value());
106 return *svc_id;
107 }
108
gatt() const109 GATT* gatt() const { return gatt_.get(); }
110
fake_client() const111 testing::FakeClient::WeakPtr fake_client() const { return fake_client_weak_; }
take_client()112 std::unique_ptr<Client> take_client() { return std::move(client_); }
113
114 private:
115 std::unique_ptr<GATT> gatt_;
116 std::unique_ptr<Client> client_;
117 testing::FakeClient::WeakPtr fake_client_weak_;
118
119 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(GattTest);
120 };
121
TEST_F(GattTest,RemoteServiceWatcherNotifiesAddedModifiedAndRemovedService)122 TEST_F(GattTest, RemoteServiceWatcherNotifiesAddedModifiedAndRemovedService) {
123 const att::Handle kGattSvcStartHandle(1);
124 const att::Handle kSvcChangedChrcHandle(2);
125 const att::Handle kSvcChangedChrcValueHandle(3);
126 const att::Handle kCCCDescriptorHandle(4);
127 const att::Handle kGattSvcEndHandle(kCCCDescriptorHandle);
128
129 ServiceData gatt_svc(ServiceKind::PRIMARY,
130 kGattSvcStartHandle,
131 kGattSvcEndHandle,
132 types::kGenericAttributeService);
133 CharacteristicData service_changed_chrc(Property::kIndicate,
134 std::nullopt,
135 kSvcChangedChrcHandle,
136 kSvcChangedChrcValueHandle,
137 types::kServiceChangedCharacteristic);
138 DescriptorData ccc_descriptor(kCCCDescriptorHandle,
139 types::kClientCharacteristicConfig);
140 fake_client()->set_services({gatt_svc});
141 fake_client()->set_characteristics({service_changed_chrc});
142 fake_client()->set_descriptors({ccc_descriptor});
143
144 // Return success when a Service Changed Client Characteristic Config
145 // descriptor write is performed.
146 int write_request_count = 0;
147 fake_client()->set_write_request_callback(
148 [&](att::Handle handle, const auto&, auto status_callback) {
149 write_request_count++;
150 EXPECT_EQ(kCCCDescriptorHandle, handle);
151 status_callback(fit::ok());
152 });
153
154 std::vector<ServiceWatcherData> svc_watcher_data;
155 gatt()->RegisterRemoteServiceWatcherForPeer(
156 kPeerId,
157 [&](std::vector<att::Handle> removed,
158 ServiceList added,
159 ServiceList modified) {
160 svc_watcher_data.push_back(
161 ServiceWatcherData{.peer_id = kPeerId,
162 .removed = std::move(removed),
163 .added = std::move(added),
164 .modified = std::move(modified)});
165 });
166
167 gatt()->AddConnection(kPeerId, take_client(), CreateMockServer);
168 RunUntilIdle();
169 EXPECT_EQ(write_request_count, 0);
170
171 gatt()->InitializeClient(kPeerId, /*service_uuids=*/{});
172 RunUntilIdle();
173 EXPECT_EQ(write_request_count, 1);
174 ASSERT_EQ(1u, svc_watcher_data.size());
175 ASSERT_EQ(1u, svc_watcher_data[0].added.size());
176 EXPECT_EQ(kPeerId, svc_watcher_data[0].peer_id);
177 EXPECT_EQ(kGattSvcStartHandle, svc_watcher_data[0].added[0]->handle());
178
179 // Add, modify, and remove a service.
180 const att::Handle kSvc1StartHandle(5);
181 const att::Handle kSvc1EndHandle(kSvc1StartHandle);
182
183 // Add a test service to ensure that service discovery occurs after the
184 // Service Changed characteristic is configured.
185 ServiceData svc1(ServiceKind::PRIMARY,
186 kSvc1StartHandle,
187 kSvc1EndHandle,
188 kTestServiceUuid0);
189 fake_client()->set_services({gatt_svc, svc1});
190
191 // Send a notification that svc1 has been added.
192 StaticByteBuffer svc_changed_range_buffer(
193 LowerBits(kSvc1StartHandle),
194 UpperBits(kSvc1StartHandle), // start handle of affected range
195 LowerBits(kSvc1EndHandle),
196 UpperBits(kSvc1EndHandle) // end handle of affected range
197 );
198 fake_client()->SendNotification(/*indicate=*/true,
199 kSvcChangedChrcValueHandle,
200 svc_changed_range_buffer,
201 /*maybe_truncated=*/false);
202 RunUntilIdle();
203 ASSERT_EQ(2u, svc_watcher_data.size());
204 ASSERT_EQ(1u, svc_watcher_data[1].added.size());
205 EXPECT_EQ(0u, svc_watcher_data[1].removed.size());
206 EXPECT_EQ(0u, svc_watcher_data[1].modified.size());
207 EXPECT_EQ(kPeerId, svc_watcher_data[1].peer_id);
208 EXPECT_EQ(kSvc1StartHandle, svc_watcher_data[1].added[0]->handle());
209 bool original_service_removed = false;
210 svc_watcher_data[1].added[0]->AddRemovedHandler(
211 [&]() { original_service_removed = true; });
212
213 // Send a notification that svc1 has been modified.
214 fake_client()->SendNotification(/*indicate=*/true,
215 kSvcChangedChrcValueHandle,
216 svc_changed_range_buffer,
217 /*maybe_truncated=*/false);
218 RunUntilIdle();
219 EXPECT_TRUE(original_service_removed);
220 ASSERT_EQ(3u, svc_watcher_data.size());
221 EXPECT_EQ(0u, svc_watcher_data[2].added.size());
222 EXPECT_EQ(0u, svc_watcher_data[2].removed.size());
223 ASSERT_EQ(1u, svc_watcher_data[2].modified.size());
224 EXPECT_EQ(kPeerId, svc_watcher_data[2].peer_id);
225 EXPECT_EQ(kSvc1StartHandle, svc_watcher_data[2].modified[0]->handle());
226 bool modified_service_removed = false;
227 svc_watcher_data[2].modified[0]->AddRemovedHandler(
228 [&]() { modified_service_removed = true; });
229
230 // Remove the service.
231 fake_client()->set_services({gatt_svc});
232
233 // Send a notification that svc1 has been removed.
234 fake_client()->SendNotification(/*indicate=*/true,
235 kSvcChangedChrcValueHandle,
236 svc_changed_range_buffer,
237 /*maybe_truncated=*/false);
238 RunUntilIdle();
239 EXPECT_TRUE(modified_service_removed);
240 ASSERT_EQ(4u, svc_watcher_data.size());
241 EXPECT_EQ(0u, svc_watcher_data[3].added.size());
242 ASSERT_EQ(1u, svc_watcher_data[3].removed.size());
243 EXPECT_EQ(0u, svc_watcher_data[3].modified.size());
244 EXPECT_EQ(kPeerId, svc_watcher_data[3].peer_id);
245 EXPECT_EQ(kSvc1StartHandle, svc_watcher_data[3].removed[0]);
246 }
247
248 // Register 3 service watchers, 2 of which are for the same peer. Then
249 // unregister 2 service watchers (one for each peer) and ensure only the third
250 // is called.
TEST_F(GattTest,MultipleRegisterRemoteServiceWatcherForPeers)251 TEST_F(GattTest, MultipleRegisterRemoteServiceWatcherForPeers) {
252 // Configure peer 0 with 1 service.
253 const att::Handle kSvcStartHandle0(42);
254 const att::Handle kSvcEndHandle0(kSvcStartHandle0);
255 ServiceData svc_data_0(ServiceKind::PRIMARY,
256 kSvcStartHandle0,
257 kSvcEndHandle0,
258 kTestServiceUuid0);
259 auto client_0 = std::make_unique<testing::FakeClient>(dispatcher());
260 client_0->set_services({svc_data_0});
261
262 gatt()->AddConnection(kPeerId0, std::move(client_0), CreateMockServer);
263
264 std::vector<ServiceWatcherData> watcher_data_0;
265 GATT::RemoteServiceWatcherId id_0 =
266 gatt()->RegisterRemoteServiceWatcherForPeer(
267 kPeerId0,
268 [&](std::vector<att::Handle> removed,
269 ServiceList added,
270 ServiceList modified) {
271 watcher_data_0.push_back(
272 ServiceWatcherData{.peer_id = kPeerId0,
273 .removed = std::move(removed),
274 .added = std::move(added),
275 .modified = std::move(modified)});
276 });
277
278 // Configure peer 1 with gatt service.
279 const att::Handle kGattSvcStartHandle(1);
280 const att::Handle kSvcChangedChrcHandle(2);
281 const att::Handle kSvcChangedChrcValueHandle(3);
282 const att::Handle kCCCDescriptorHandle(4);
283 const att::Handle kGattSvcEndHandle(kCCCDescriptorHandle);
284 ServiceData gatt_svc(ServiceKind::PRIMARY,
285 kGattSvcStartHandle,
286 kGattSvcEndHandle,
287 types::kGenericAttributeService);
288 CharacteristicData service_changed_chrc(Property::kIndicate,
289 std::nullopt,
290 kSvcChangedChrcHandle,
291 kSvcChangedChrcValueHandle,
292 types::kServiceChangedCharacteristic);
293 DescriptorData ccc_descriptor(kCCCDescriptorHandle,
294 types::kClientCharacteristicConfig);
295 auto client_1 = std::make_unique<testing::FakeClient>(dispatcher());
296 auto client_1_weak = client_1.get();
297 client_1->set_services({gatt_svc});
298 client_1->set_characteristics({service_changed_chrc});
299 client_1->set_descriptors({ccc_descriptor});
300
301 // Return success when a Service Changed Client Characteristic Config
302 // descriptor write is performed.
303 client_1->set_write_request_callback(
304 [&](att::Handle, const auto&, auto status_callback) {
305 status_callback(fit::ok());
306 });
307
308 gatt()->AddConnection(kPeerId1, std::move(client_1), CreateMockServer);
309
310 // Register 2 watchers for kPeerId1.
311 std::vector<ServiceWatcherData> watcher_data_1;
312 GATT::RemoteServiceWatcherId id_1 =
313 gatt()->RegisterRemoteServiceWatcherForPeer(
314 kPeerId1,
315 [&](std::vector<att::Handle> removed,
316 ServiceList added,
317 ServiceList modified) {
318 watcher_data_1.push_back(
319 ServiceWatcherData{.peer_id = kPeerId1,
320 .removed = std::move(removed),
321 .added = std::move(added),
322 .modified = std::move(modified)});
323 });
324 EXPECT_NE(id_0, id_1);
325
326 std::vector<ServiceWatcherData> watcher_data_2;
327 gatt()->RegisterRemoteServiceWatcherForPeer(
328 kPeerId1,
329 [&](std::vector<att::Handle> removed,
330 ServiceList added,
331 ServiceList modified) {
332 watcher_data_2.push_back(
333 ServiceWatcherData{.peer_id = kPeerId1,
334 .removed = std::move(removed),
335 .added = std::move(added),
336 .modified = std::move(modified)});
337 });
338
339 // Service discovery should complete and all service watchers should be
340 // notified.
341 gatt()->InitializeClient(kPeerId0, /*service_uuids=*/{});
342 gatt()->InitializeClient(kPeerId1, /*service_uuids=*/{});
343 RunUntilIdle();
344 ASSERT_EQ(watcher_data_0.size(), 1u);
345 ASSERT_EQ(watcher_data_0[0].added.size(), 1u);
346 EXPECT_EQ(watcher_data_0[0].added[0]->handle(), kSvcStartHandle0);
347
348 ASSERT_EQ(watcher_data_1.size(), 1u);
349 ASSERT_EQ(watcher_data_1[0].added.size(), 1u);
350 EXPECT_EQ(watcher_data_1[0].added[0]->handle(), kGattSvcStartHandle);
351
352 ASSERT_EQ(watcher_data_2.size(), 1u);
353 ASSERT_EQ(watcher_data_2[0].added.size(), 1u);
354 EXPECT_EQ(watcher_data_2[0].added[0]->handle(), kGattSvcStartHandle);
355
356 gatt()->UnregisterRemoteServiceWatcher(id_0);
357 gatt()->UnregisterRemoteServiceWatcher(id_1);
358
359 const att::Handle kSvcStartHandle1(84);
360 const att::Handle kSvcEndHandle1(kSvcStartHandle1);
361 ServiceData svc_data_1(ServiceKind::PRIMARY,
362 kSvcStartHandle1,
363 kSvcEndHandle1,
364 kTestServiceUuid0);
365 client_1_weak->set_services({gatt_svc, svc_data_1});
366
367 // Send a notification that service kSvcStartHandle1 has been added.
368 StaticByteBuffer svc_changed_range_buffer(
369 LowerBits(kSvcStartHandle1),
370 UpperBits(kSvcStartHandle1), // start handle of affected range
371 LowerBits(kSvcEndHandle1),
372 UpperBits(kSvcEndHandle1) // end handle of affected range
373 );
374 client_1_weak->SendNotification(/*indicate=*/true,
375 kSvcChangedChrcValueHandle,
376 svc_changed_range_buffer,
377 /*maybe_truncated=*/false);
378 RunUntilIdle();
379 // Unregistered handlers should not be notified.
380 ASSERT_EQ(watcher_data_0.size(), 1u);
381 ASSERT_EQ(watcher_data_1.size(), 1u);
382
383 // Still registered handler should be notified of added service.
384 ASSERT_EQ(watcher_data_2.size(), 2u);
385 ASSERT_EQ(watcher_data_2[1].added.size(), 1u);
386 EXPECT_EQ(watcher_data_2[1].added[0]->handle(), kSvcStartHandle1);
387 }
388
TEST_F(GattTest,ServiceDiscoveryFailureShutsDownConnection)389 TEST_F(GattTest, ServiceDiscoveryFailureShutsDownConnection) {
390 testing::MockServer::WeakPtr mock_server;
391 auto mock_server_factory = [&](PeerId peer_id,
392 LocalServiceManager::WeakPtr local_services) {
393 auto unique_mock_server = std::make_unique<testing::MockServer>(
394 peer_id, std::move(local_services));
395 mock_server = unique_mock_server->AsMockWeakPtr();
396 return unique_mock_server;
397 };
398 fake_client()->set_discover_services_callback([](ServiceKind) {
399 return ToResult(att::ErrorCode::kRequestNotSupported);
400 });
401 gatt()->AddConnection(kPeerId, take_client(), std::move(mock_server_factory));
402 ASSERT_TRUE(mock_server.is_alive());
403 EXPECT_FALSE(mock_server->was_shut_down());
404 gatt()->InitializeClient(kPeerId, std::vector<UUID>{});
405 RunUntilIdle();
406 EXPECT_TRUE(mock_server->was_shut_down());
407 }
408
TEST_F(GattTest,SendIndicationNoConnectionFails)409 TEST_F(GattTest, SendIndicationNoConnectionFails) {
410 att::Result<> res = fit::ok();
411 auto indicate_cb = [&res](att::Result<> cb_res) { res = cb_res; };
412 // Don't add the connection to GATT before trying to send an indication
413 gatt()->SendUpdate(/*service_id=*/1,
414 /*chrc_id=*/2,
415 PeerId{3},
416 std::vector<uint8_t>{1},
417 std::move(indicate_cb));
418 EXPECT_EQ(fit::failed(), res);
419 }
420
421 class GattTestBoolParam : public GattTest,
422 public ::testing::WithParamInterface<bool> {};
423
TEST_P(GattTestBoolParam,SendIndicationReceiveResponse)424 TEST_P(GattTestBoolParam, SendIndicationReceiveResponse) {
425 testing::MockServer::WeakPtr mock_server;
426 auto mock_server_factory = [&](PeerId peer_id,
427 LocalServiceManager::WeakPtr local_services) {
428 auto unique_mock_server = std::make_unique<testing::MockServer>(
429 peer_id, std::move(local_services));
430 mock_server = unique_mock_server->AsMockWeakPtr();
431 return unique_mock_server;
432 };
433 gatt()->AddConnection(kPeerId, take_client(), std::move(mock_server_factory));
434 ASSERT_TRUE(mock_server.is_alive());
435
436 // Configure how the mock server handles updates sent from the GATT object.
437 IndicationCallback mock_ind_cb = nullptr;
438 const std::vector<uint8_t> kIndicateVal{114}; // 114 is arbitrary
439 testing::UpdateHandler handler = [&](auto /*ignore*/,
440 auto /*ignore*/,
441 const ByteBuffer& bytes,
442 IndicationCallback ind_cb) {
443 EXPECT_EQ(kIndicateVal, bytes.ToVector());
444 mock_ind_cb = std::move(ind_cb);
445 };
446 mock_server->set_update_handler(std::move(handler));
447
448 // Registering the service isn't strictly necessary as gatt::GATT itself is
449 // not responsible for checking that a service exists before sending an
450 // update, but it's a more realistic test.
451 IdType svc_id = RegisterArbitraryService();
452
453 std::optional<att::Result<>> indicate_status;
454 auto indicate_cb = [&](att::Result<> status) { indicate_status = status; };
455 gatt()->SendUpdate(
456 svc_id, kChrcId, kPeerId, kIndicateVal, std::move(indicate_cb));
457 RunUntilIdle();
458 EXPECT_TRUE(mock_ind_cb);
459 EXPECT_FALSE(indicate_status.has_value());
460 if (GetParam()) {
461 mock_ind_cb(fit::ok());
462 ASSERT_TRUE(indicate_status.has_value());
463 EXPECT_TRUE(indicate_status->is_ok());
464 } else {
465 mock_ind_cb(ToResult(HostError::kTimedOut));
466 ASSERT_TRUE(indicate_status.has_value());
467 EXPECT_EQ(ToResult(HostError::kTimedOut), *indicate_status);
468 }
469 }
470
471 INSTANTIATE_TEST_SUITE_P(GattTestBoolParamTests,
472 GattTestBoolParam,
473 ::testing::Bool());
474
TEST_F(GattTest,NotifyConnectedPeersNoneConnectedDoesntCrash)475 TEST_F(GattTest, NotifyConnectedPeersNoneConnectedDoesntCrash) {
476 // Registering a service isn't strictly necessary, but makes for a more
477 // realistic test.
478 IdType svc_id = RegisterArbitraryService();
479
480 const std::vector<uint8_t> kNotifyVal{12u};
481 gatt()->UpdateConnectedPeers(
482 svc_id, kChrcId, kNotifyVal, /*indicate_cb=*/nullptr);
483 RunUntilIdle();
484 }
485
TEST_F(GattTest,NotifyConnectedPeerWithConnectionDoesntCrash)486 TEST_F(GattTest, NotifyConnectedPeerWithConnectionDoesntCrash) {
487 // Registering a service isn't strictly necessary, but makes for a more
488 // realistic test.
489 IdType svc_id = RegisterArbitraryService();
490
491 testing::MockServer::WeakPtr mock_server;
492 auto mock_server_factory = [&](PeerId peer_id,
493 LocalServiceManager::WeakPtr local_services) {
494 auto unique_mock_server = std::make_unique<testing::MockServer>(
495 peer_id, std::move(local_services));
496 mock_server = unique_mock_server->AsMockWeakPtr();
497 return unique_mock_server;
498 };
499 gatt()->AddConnection(kPeerId, take_client(), std::move(mock_server_factory));
500 ASSERT_TRUE(mock_server.is_alive());
501
502 // Configure how the mock server handles updates sent from the GATT object.
503 IndicationCallback mock_ind_cb = [](att::Result<>) {}; // no-op, but not-null
504 const std::vector<uint8_t> kNotifyVal{12u};
505 testing::UpdateHandler handler = [&](auto /*ignore*/,
506 auto /*ignore*/,
507 const ByteBuffer& bytes,
508 IndicationCallback ind_cb) {
509 EXPECT_EQ(kNotifyVal, bytes.ToVector());
510 mock_ind_cb = std::move(ind_cb);
511 };
512 mock_server->set_update_handler(std::move(handler));
513 gatt()->UpdateConnectedPeers(
514 svc_id, kChrcId, kNotifyVal, /*indicate_cb=*/nullptr);
515 RunUntilIdle();
516 EXPECT_EQ(nullptr, mock_ind_cb);
517 }
518
TEST_F(GattTest,IndicateConnectedPeersNoneConnectedSucceeds)519 TEST_F(GattTest, IndicateConnectedPeersNoneConnectedSucceeds) {
520 // Registering a service isn't strictly necessary, but makes for a more
521 // realistic test.
522 IdType svc_id = RegisterArbitraryService();
523
524 const std::vector<uint8_t> indicate_val{12u};
525 att::Result<> res = ToResult(att::ErrorCode::kAttributeNotFound);
526 auto indicate_cb = [&](att::Result<> cb_res) { res = cb_res; };
527 gatt()->UpdateConnectedPeers(
528 svc_id, kChrcId, indicate_val, std::move(indicate_cb));
529
530 EXPECT_EQ(fit::ok(), res);
531 }
532
533 struct PeerIdAndMtu {
534 PeerId peer_id;
535 uint16_t mtu;
536 };
TEST_F(GattTest,UpdateMtuListenersNotified)537 TEST_F(GattTest, UpdateMtuListenersNotified) {
538 // Add MTU listeners to GATT
539 std::optional<PeerIdAndMtu> listener_1_results;
540 auto listener_1 = [&](PeerId peer_id, uint16_t mtu) {
541 listener_1_results = PeerIdAndMtu{.peer_id = peer_id, .mtu = mtu};
542 };
543 std::optional<PeerIdAndMtu> listener_2_results;
544 auto listener_2 = [&](PeerId peer_id, uint16_t mtu) {
545 listener_2_results = PeerIdAndMtu{.peer_id = peer_id, .mtu = mtu};
546 };
547 gatt()->RegisterPeerMtuListener(std::move(listener_1));
548 GATT::PeerMtuListenerId listener_2_id =
549 gatt()->RegisterPeerMtuListener(std::move(listener_2));
550
551 // Configure MTU
552 const uint16_t kExpectedMtu = att::kLEMinMTU + 1;
553 fake_client()->set_server_mtu(kExpectedMtu);
554
555 // Add connection, initialize, and verify that MTU exchange succeeds
556 gatt()->AddConnection(kPeerId0, take_client(), CreateMockServer);
557 gatt()->InitializeClient(kPeerId0, {});
558 RunUntilIdle();
559
560 ASSERT_TRUE(listener_1_results.has_value());
561 EXPECT_EQ(kPeerId0, listener_1_results->peer_id);
562 EXPECT_EQ(kExpectedMtu, listener_1_results->mtu);
563 ASSERT_TRUE(listener_2_results.has_value());
564 EXPECT_EQ(kPeerId0, listener_2_results->peer_id);
565 EXPECT_EQ(kExpectedMtu, listener_2_results->mtu);
566
567 // After unregistering listener_2, only listener_1 should be notified for the
568 // next update
569 listener_1_results.reset();
570 listener_2_results.reset();
571 EXPECT_TRUE(gatt()->UnregisterPeerMtuListener(listener_2_id));
572 auto client_2 = std::make_unique<testing::FakeClient>(dispatcher());
573 const uint16_t kNewExpectedMtu = kExpectedMtu + 1;
574 client_2->set_server_mtu(kNewExpectedMtu);
575 gatt()->AddConnection(kPeerId1, std::move(client_2), CreateMockServer);
576 gatt()->InitializeClient(kPeerId1, {});
577 RunUntilIdle();
578
579 ASSERT_TRUE(listener_1_results.has_value());
580 EXPECT_EQ(kPeerId1, listener_1_results->peer_id);
581 EXPECT_EQ(kNewExpectedMtu, listener_1_results->mtu);
582 EXPECT_FALSE(listener_2_results.has_value());
583 }
584
TEST_F(GattTest,MtuExchangeServerNotSupportedListenersNotifiedDefaultMtu)585 TEST_F(GattTest, MtuExchangeServerNotSupportedListenersNotifiedDefaultMtu) {
586 // Add MTU listeners to GATT
587 std::optional<PeerIdAndMtu> listener_1_results;
588 auto listener_1 = [&](PeerId peer_id, uint16_t mtu) {
589 listener_1_results = PeerIdAndMtu{.peer_id = peer_id, .mtu = mtu};
590 };
591 std::optional<PeerIdAndMtu> listener_2_results;
592 auto listener_2 = [&](PeerId peer_id, uint16_t mtu) {
593 listener_2_results = PeerIdAndMtu{.peer_id = peer_id, .mtu = mtu};
594 };
595 gatt()->RegisterPeerMtuListener(std::move(listener_1));
596 gatt()->RegisterPeerMtuListener(std::move(listener_2));
597
598 // It should be OK for the MTU exchange to fail with kRequestNotSupported, in
599 // which case we use the default LE MTU per v5.3 Vol. 3 Part G 4.3.1 (not the
600 // Server MTU)
601 fake_client()->set_server_mtu(att::kLEMinMTU + 5);
602 fake_client()->set_exchange_mtu_status(
603 ToResult(att::ErrorCode::kRequestNotSupported));
604 gatt()->AddConnection(kPeerId0, take_client(), CreateMockServer);
605 gatt()->InitializeClient(kPeerId0, {});
606 RunUntilIdle();
607
608 ASSERT_TRUE(listener_1_results.has_value());
609 EXPECT_EQ(kPeerId0, listener_1_results->peer_id);
610 EXPECT_EQ(att::kLEMinMTU, listener_1_results->mtu);
611 ASSERT_TRUE(listener_2_results.has_value());
612 EXPECT_EQ(kPeerId0, listener_2_results->peer_id);
613 EXPECT_EQ(att::kLEMinMTU, listener_2_results->mtu);
614 }
615
TEST_F(GattTest,MtuExchangeFailsListenersNotNotifiedConnectionShutdown)616 TEST_F(GattTest, MtuExchangeFailsListenersNotNotifiedConnectionShutdown) {
617 // Add MTU listener to GATT
618 bool listener_invoked = false;
619 auto listener = [&](PeerId /*ignore*/, uint16_t /*ignore*/) {
620 listener_invoked = true;
621 };
622 gatt()->RegisterPeerMtuListener(std::move(listener));
623
624 // Configure MTU exchange to fail
625 fake_client()->set_exchange_mtu_status(ToResult(HostError::kFailed));
626
627 // Track mock server
628 testing::MockServer::WeakPtr mock_server;
629 auto mock_server_factory = [&](PeerId peer_id,
630 LocalServiceManager::WeakPtr local_services) {
631 auto unique_mock_server = std::make_unique<testing::MockServer>(
632 peer_id, std::move(local_services));
633 mock_server = unique_mock_server->AsMockWeakPtr();
634 return unique_mock_server;
635 };
636
637 // Add connection, initialize, and verify that MTU exchange failure causes
638 // connection shutdown.
639 gatt()->AddConnection(
640 kPeerId0, take_client(), std::move(mock_server_factory));
641 gatt()->InitializeClient(kPeerId0, {});
642 RunUntilIdle();
643 EXPECT_FALSE(listener_invoked);
644 ASSERT_TRUE(mock_server.is_alive());
645 EXPECT_TRUE(mock_server->was_shut_down());
646 }
647
648 const std::vector<uint8_t> kIndicateVal{12u};
649 class GattIndicateMultipleConnectedPeersTest : public GattTest {
650 protected:
SetUp()651 void SetUp() override {
652 GattTest::SetUp();
653 // Registering a service isn't strictly necessary, but makes for a more
654 // realistic test.
655 svc_id_ = RegisterArbitraryService();
656
657 // Add first connection
658 auto mock_server_factory_0 =
659 [&](PeerId peer_id, LocalServiceManager::WeakPtr local_services) {
660 auto unique_mock_server = std::make_unique<testing::MockServer>(
661 peer_id, std::move(local_services));
662 mock_server_0_ = unique_mock_server->AsMockWeakPtr();
663 return unique_mock_server;
664 };
665 gatt()->AddConnection(kPeerId0,
666 std::make_unique<testing::FakeClient>(dispatcher()),
667 std::move(mock_server_factory_0));
668 ASSERT_TRUE(mock_server_0_.is_alive());
669
670 // Add second connection
671 auto mock_server_factory_1 =
672 [&](PeerId peer_id, LocalServiceManager::WeakPtr local_services) {
673 auto unique_mock_server = std::make_unique<testing::MockServer>(
674 peer_id, std::move(local_services));
675 mock_server_1_ = unique_mock_server->AsMockWeakPtr();
676 return unique_mock_server;
677 };
678 gatt()->AddConnection(kPeerId1,
679 std::make_unique<testing::FakeClient>(dispatcher()),
680 std::move(mock_server_factory_1));
681 ASSERT_TRUE(mock_server_1_.is_alive());
682
683 // Configure how the mock servers handle updates from the GATT object.
684 testing::UpdateHandler handler_0 = [&](auto /*ignore*/,
685 auto /*ignore*/,
686 const ByteBuffer& bytes,
687 IndicationCallback ind_cb) {
688 EXPECT_EQ(kIndicateVal, bytes.ToVector());
689 indication_ack_cb_0_ = std::move(ind_cb);
690 };
691 mock_server_0_->set_update_handler(std::move(handler_0));
692
693 testing::UpdateHandler handler_1 = [&](auto /*ignore*/,
694 auto /*ignore*/,
695 const ByteBuffer& bytes,
696 IndicationCallback ind_cb) {
697 EXPECT_EQ(kIndicateVal, bytes.ToVector());
698 indication_ack_cb_1_ = std::move(ind_cb);
699 };
700 mock_server_1_->set_update_handler(std::move(handler_1));
701 }
702
703 IndicationCallback indication_ack_cb_0_;
704 IndicationCallback indication_ack_cb_1_;
705 IdType svc_id_;
706 testing::MockServer::WeakPtr mock_server_0_;
707 testing::MockServer::WeakPtr mock_server_1_;
708 };
709
TEST_F(GattIndicateMultipleConnectedPeersTest,UpdateConnectedPeersWaitsTillAllCallbacksComplete)710 TEST_F(GattIndicateMultipleConnectedPeersTest,
711 UpdateConnectedPeersWaitsTillAllCallbacksComplete) {
712 // Send an indication.
713 att::Result<> res =
714 ToResult(att::ErrorCode::kInvalidPDU); // arbitrary error code
715 IndicationCallback indication_cb = [&res](att::Result<> cb_res) {
716 res = cb_res;
717 };
718 gatt()->UpdateConnectedPeers(
719 svc_id_, kChrcId, kIndicateVal, indication_cb.share());
720 RunUntilIdle();
721 ASSERT_TRUE(indication_ack_cb_0_);
722 ASSERT_TRUE(indication_ack_cb_1_);
723
724 // The UpdateConnectedPeers callback shouldn't resolved when the first
725 // indication is ACKed.
726 indication_ack_cb_0_(fit::ok());
727 RunUntilIdle();
728 EXPECT_EQ(ToResult(att::ErrorCode::kInvalidPDU), res);
729
730 indication_ack_cb_1_(fit::ok());
731 RunUntilIdle();
732 EXPECT_EQ(fit::ok(), res);
733 }
734
TEST_F(GattIndicateMultipleConnectedPeersTest,OneFailsNextSucceedsOnlyFailureNotified)735 TEST_F(GattIndicateMultipleConnectedPeersTest,
736 OneFailsNextSucceedsOnlyFailureNotified) {
737 std::optional<att::Result<>> res;
738 IndicationCallback indication_cb = [&res](att::Result<> cb_res) {
739 res = cb_res;
740 };
741 gatt()->UpdateConnectedPeers(
742 svc_id_, kChrcId, kIndicateVal, indication_cb.share());
743 RunUntilIdle();
744 EXPECT_EQ(std::nullopt, res);
745 ASSERT_TRUE(indication_ack_cb_0_);
746 ASSERT_TRUE(indication_ack_cb_1_);
747
748 indication_ack_cb_0_(ToResult(att::ErrorCode::kRequestNotSupported));
749 EXPECT_EQ(ToResult(att::ErrorCode::kRequestNotSupported), res);
750
751 // Acking the next indication should not cause the callback to be invoked
752 // again with success.
753 indication_ack_cb_1_(fit::ok());
754 EXPECT_EQ(ToResult(att::ErrorCode::kRequestNotSupported), res);
755 }
756
757 } // namespace
758 } // namespace bt::gatt::internal
759