1 // Copyright 2024 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/fuchsia/host/fidl/low_energy_central_server.h"
16 
17 #include <cpp-string/string_printf.h>
18 #include <gmock/gmock.h>
19 
20 #include <cstddef>
21 
22 #include "fuchsia/bluetooth/gatt/cpp/fidl.h"
23 #include "fuchsia/bluetooth/le/cpp/fidl.h"
24 #include "lib/fidl/cpp/interface_request.h"
25 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/adapter_test_fixture.h"
26 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/fake_adapter_test_fixture.h"
27 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/helpers.h"
28 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/measure_tape/hlcpp_measure_tape_for_peer.h"
29 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
30 #include "pw_bluetooth_sapphire/internal/host/testing/fake_controller.h"
31 #include "pw_bluetooth_sapphire/internal/host/testing/fake_peer.h"
32 
33 namespace bthost {
34 namespace {
35 
36 namespace fble = fuchsia::bluetooth::le;
37 namespace fgatt = fuchsia::bluetooth::gatt;
38 
39 const bt::DeviceAddress kTestAddr(bt::DeviceAddress::Type::kLEPublic,
40                                   {0x01, 0, 0, 0, 0, 0});
41 const size_t kLEMaxNumPackets = 10;
42 const bt::hci::DataBufferInfo kLEDataBufferInfo(
43     bt::hci_spec::kMaxACLPayloadSize, kLEMaxNumPackets);
44 
ScanOptionsWithEmptyFilter()45 fble::ScanOptions ScanOptionsWithEmptyFilter() {
46   fble::ScanOptions options;
47   fble::Filter filter;
48   std::vector<fble::Filter> filters;
49   filters.emplace_back(std::move(filter));
50   options.set_filters(std::move(filters));
51   return options;
52 }
53 
MaxPeersPerScanResultWatcherChannel(const bt::gap::Peer & peer)54 size_t MaxPeersPerScanResultWatcherChannel(const bt::gap::Peer& peer) {
55   const size_t kPeerSize = measure_tape::fuchsia::bluetooth::le::Measure(
56                                fidl_helpers::PeerToFidlLe(peer))
57                                .num_bytes;
58   const size_t kVectorOverhead =
59       sizeof(fidl_message_header_t) + sizeof(fidl_vector_t);
60   const size_t kMaxBytes = ZX_CHANNEL_MAX_MSG_BYTES - kVectorOverhead;
61   return kMaxBytes / kPeerSize;
62 }
63 
64 using TestingBase = bthost::testing::AdapterTestFixture;
65 
66 class LowEnergyCentralServerTest : public TestingBase {
67  public:
68   LowEnergyCentralServerTest() = default;
69   ~LowEnergyCentralServerTest() override = default;
70 
SetUp()71   void SetUp() override {
72     AdapterTestFixture::SetUp();
73 
74     // Create a LowEnergyCentralServer and bind it to a local client.
75     fidl::InterfaceHandle<fble::Central> handle;
76     gatt_ = take_gatt();
77     server_ = std::make_unique<LowEnergyCentralServer>(
78         adapter(), handle.NewRequest(), gatt_->GetWeakPtr());
79     proxy_.Bind(std::move(handle));
80 
81     bt::testing::FakeController::Settings settings;
82     settings.ApplyLegacyLEConfig();
83     test_device()->set_settings(settings);
84   }
85 
TearDown()86   void TearDown() override {
87     RunLoopUntilIdle();
88 
89     proxy_ = nullptr;
90     server_ = nullptr;
91     gatt_ = nullptr;
92 
93     RunLoopUntilIdle();
94     AdapterTestFixture::TearDown();
95   }
96 
97  protected:
98   // Returns true if the given gatt.Client handle was closed after the event
99   // loop finishes processing. Returns false if the handle was not closed.
100   // Ownership of |handle| remains with the caller when this method returns.
IsClientHandleClosedAfterLoop(fidl::InterfaceHandle<fgatt::Client> * handle)101   bool IsClientHandleClosedAfterLoop(
102       fidl::InterfaceHandle<fgatt::Client>* handle) {
103     PW_CHECK(handle);
104 
105     fgatt::ClientPtr proxy;
106     proxy.Bind(std::move(*handle));
107 
108     bool closed = false;
109     proxy.set_error_handler([&](zx_status_t s) {
110       EXPECT_EQ(ZX_ERR_PEER_CLOSED, s);
111       closed = true;
112     });
113     RunLoopUntilIdle();
114 
115     *handle = proxy.Unbind();
116     return closed;
117   }
118 
119   // Destroys the FIDL server. The le.Central proxy will be shut down and
120   // subsequent calls to `server()` will return nullptr.
DestroyServer()121   void DestroyServer() { server_ = nullptr; }
122 
server() const123   LowEnergyCentralServer* server() const { return server_.get(); }
central_proxy() const124   fuchsia::bluetooth::le::Central* central_proxy() const {
125     return proxy_.get();
126   }
127 
128  private:
129   std::unique_ptr<LowEnergyCentralServer> server_;
130   fble::CentralPtr proxy_;
131   std::unique_ptr<bt::gatt::GATT> gatt_;
132 
133   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyCentralServerTest);
134 };
135 
136 class LowEnergyCentralServerTestFakeAdapter
137     : public bt::fidl::testing::FakeAdapterTestFixture {
138  public:
SetUp()139   void SetUp() override {
140     bt::fidl::testing::FakeAdapterTestFixture::SetUp();
141 
142     // Create a LowEnergyCentralServer and bind it to a local client.
143     fidl::InterfaceHandle<fble::Central> handle;
144     gatt_ = std::make_unique<bt::gatt::testing::FakeLayer>(pw_dispatcher());
145     server_ = std::make_unique<LowEnergyCentralServer>(
146         adapter()->AsWeakPtr(), handle.NewRequest(), gatt_->GetWeakPtr());
147     proxy_.Bind(std::move(handle));
148   }
149 
central_proxy() const150   fuchsia::bluetooth::le::Central* central_proxy() const {
151     return proxy_.get();
152   }
153 
154  private:
155   std::unique_ptr<LowEnergyCentralServer> server_;
156   fble::CentralPtr proxy_;
157   std::unique_ptr<bt::gatt::GATT> gatt_;
158 };
159 
160 class LowEnergyCentralServerTestFakeAdapterBoolParam
161     : public LowEnergyCentralServerTestFakeAdapter,
162       public ::testing::WithParamInterface<bool> {};
163 
164 // Tests that connecting to a peripheral with
165 // LowEnergyConnectionOptions.bondable_mode unset results in a bondable
166 // connection ref being stored in LowEnergyConnectionManager
TEST_F(LowEnergyCentralServerTest,ConnectDefaultResultsBondableConnectionRef)167 TEST_F(LowEnergyCentralServerTest, ConnectDefaultResultsBondableConnectionRef) {
168   auto* const peer =
169       adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/true);
170   ASSERT_TRUE(peer);
171 
172   test_device()->AddPeer(
173       std::make_unique<bt::testing::FakePeer>(kTestAddr, pw_dispatcher()));
174 
175   fble::ConnectionOptions options;
176 
177   fidl::InterfaceHandle<fuchsia::bluetooth::gatt::Client> gatt_client;
178   fidl::InterfaceRequest<fuchsia::bluetooth::gatt::Client> gatt_client_req =
179       gatt_client.NewRequest();
180 
181   auto status = fidl_helpers::NewFidlError(
182       fuchsia::bluetooth::ErrorCode::BAD_STATE, "this should change");
183   auto callback = [&status](::fuchsia::bluetooth::Status cb_status) {
184     ASSERT_EQ(cb_status.error, nullptr);
185     status = std::move(cb_status);
186   };
187   central_proxy()->ConnectPeripheral(peer->identifier().ToString(),
188                                      std::move(options),
189                                      std::move(gatt_client_req),
190                                      callback);
191   ASSERT_FALSE(server()->FindConnectionForTesting(peer->identifier()));
192   RunLoopUntilIdle();
193   auto conn_ref = server()->FindConnectionForTesting(peer->identifier());
194   ASSERT_EQ(status.error, nullptr);
195   ASSERT_TRUE(conn_ref.has_value());
196   ASSERT_TRUE(conn_ref.value());
197   ASSERT_EQ(conn_ref.value()->bondable_mode(), bt::sm::BondableMode::Bondable);
198 }
199 
200 // Tests that setting LowEnergyConnectionOptions.bondable_mode to true and
201 // connecting to a peer in bondable mode results in a bondable connection ref
202 // being stored in LowEnergyConnectionManager
TEST_F(LowEnergyCentralServerTest,ConnectBondableResultsBondableConnectionRef)203 TEST_F(LowEnergyCentralServerTest,
204        ConnectBondableResultsBondableConnectionRef) {
205   auto* const peer =
206       adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/true);
207   ASSERT_TRUE(peer);
208 
209   test_device()->AddPeer(
210       std::make_unique<bt::testing::FakePeer>(kTestAddr, pw_dispatcher()));
211 
212   fble::ConnectionOptions options;
213   options.set_bondable_mode(true);
214 
215   fidl::InterfaceHandle<fuchsia::bluetooth::gatt::Client> gatt_client;
216   fidl::InterfaceRequest<fuchsia::bluetooth::gatt::Client> gatt_client_req =
217       gatt_client.NewRequest();
218 
219   auto status = fidl_helpers::NewFidlError(
220       fuchsia::bluetooth::ErrorCode::BAD_STATE, "this should change");
221   auto callback = [&status](::fuchsia::bluetooth::Status cb_status) {
222     ASSERT_EQ(cb_status.error, nullptr);
223     status = std::move(cb_status);
224   };
225   central_proxy()->ConnectPeripheral(peer->identifier().ToString(),
226                                      std::move(options),
227                                      std::move(gatt_client_req),
228                                      callback);
229   ASSERT_FALSE(server()->FindConnectionForTesting(peer->identifier()));
230   RunLoopUntilIdle();
231   auto conn_ref = server()->FindConnectionForTesting(peer->identifier());
232   ASSERT_EQ(status.error, nullptr);
233   ASSERT_TRUE(conn_ref.has_value());
234   ASSERT_TRUE(conn_ref.value());
235   ASSERT_EQ(conn_ref.value()->bondable_mode(), bt::sm::BondableMode::Bondable);
236 }
237 
238 // Tests that setting LowEnergyConnectionOptions.bondable_mode to false and
239 // connecting to a peer results in a non-bondable connection ref being stored in
240 // LowEnergyConnectionManager.
TEST_F(LowEnergyCentralServerTest,ConnectNonBondableResultsNonBondableConnectionRef)241 TEST_F(LowEnergyCentralServerTest,
242        ConnectNonBondableResultsNonBondableConnectionRef) {
243   auto* const peer =
244       adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/true);
245   ASSERT_TRUE(peer);
246 
247   test_device()->AddPeer(
248       std::make_unique<bt::testing::FakePeer>(kTestAddr, pw_dispatcher()));
249 
250   fble::ConnectionOptions options;
251   options.set_bondable_mode(false);
252 
253   fidl::InterfaceHandle<fuchsia::bluetooth::gatt::Client> gatt_client;
254   fidl::InterfaceRequest<fuchsia::bluetooth::gatt::Client> gatt_client_req =
255       gatt_client.NewRequest();
256 
257   auto status = fidl_helpers::NewFidlError(
258       fuchsia::bluetooth::ErrorCode::BAD_STATE, "this should change");
259   auto callback = [&status](::fuchsia::bluetooth::Status cb_status) {
260     ASSERT_EQ(cb_status.error, nullptr);
261     status = std::move(cb_status);
262   };
263   central_proxy()->ConnectPeripheral(peer->identifier().ToString(),
264                                      std::move(options),
265                                      std::move(gatt_client_req),
266                                      callback);
267   ASSERT_FALSE(server()->FindConnectionForTesting(peer->identifier()));
268   RunLoopUntilIdle();
269   auto conn_ref = server()->FindConnectionForTesting(peer->identifier());
270   ASSERT_EQ(status.error, nullptr);
271   ASSERT_TRUE(conn_ref.has_value());
272   ASSERT_TRUE(conn_ref.value());
273   ASSERT_EQ(conn_ref.value()->bondable_mode(),
274             bt::sm::BondableMode::NonBondable);
275 }
276 
TEST_F(LowEnergyCentralServerTest,DisconnectUnconnectedPeripheralReturnsSuccess)277 TEST_F(LowEnergyCentralServerTest,
278        DisconnectUnconnectedPeripheralReturnsSuccess) {
279   auto status = fidl_helpers::NewFidlError(
280       fuchsia::bluetooth::ErrorCode::BAD_STATE, "this should change");
281   auto callback = [&status](::fuchsia::bluetooth::Status cb_status) {
282     status = std::move(cb_status);
283   };
284   central_proxy()->DisconnectPeripheral(bt::PeerId(1).ToString(),
285                                         std::move(callback));
286   RunLoopUntilIdle();
287   EXPECT_EQ(status.error, nullptr);
288 }
289 
TEST_F(LowEnergyCentralServerTest,FailedConnectionCleanedUp)290 TEST_F(LowEnergyCentralServerTest, FailedConnectionCleanedUp) {
291   auto* const peer =
292       adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/true);
293   ASSERT_TRUE(peer);
294 
295   test_device()->AddPeer(
296       std::make_unique<bt::testing::FakePeer>(kTestAddr, pw_dispatcher()));
297 
298   fble::ConnectionOptions options;
299 
300   fidl::InterfaceHandle<fuchsia::bluetooth::gatt::Client> gatt_client;
301   fidl::InterfaceRequest<fuchsia::bluetooth::gatt::Client> gatt_client_req =
302       gatt_client.NewRequest();
303 
304   fuchsia::bluetooth::Status status;
305   auto callback = [&status](::fuchsia::bluetooth::Status cb_status) {
306     status = std::move(cb_status);
307   };
308 
309   test_device()->SetDefaultCommandStatus(
310       bt::hci_spec::kReadRemoteVersionInfo,
311       pw::bluetooth::emboss::StatusCode::CONNECTION_LIMIT_EXCEEDED);
312 
313   ASSERT_FALSE(
314       server()->FindConnectionForTesting(peer->identifier()).has_value());
315   central_proxy()->ConnectPeripheral(peer->identifier().ToString(),
316                                      std::move(options),
317                                      std::move(gatt_client_req),
318                                      callback);
319   RunLoopUntilIdle();
320   auto conn = server()->FindConnectionForTesting(peer->identifier());
321   EXPECT_NE(status.error, nullptr);
322   EXPECT_FALSE(conn.has_value());
323 }
324 
TEST_F(LowEnergyCentralServerTest,ConnectPeripheralAlreadyConnectedInLecm)325 TEST_F(LowEnergyCentralServerTest, ConnectPeripheralAlreadyConnectedInLecm) {
326   auto* const peer =
327       adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/true);
328   test_device()->AddPeer(
329       std::make_unique<bt::testing::FakePeer>(kTestAddr, pw_dispatcher()));
330 
331   std::unique_ptr<bt::gap::LowEnergyConnectionHandle> le_conn;
332   adapter()->le()->Connect(
333       peer->identifier(),
334       [&le_conn](auto result) {
335         ASSERT_EQ(fit::ok(), result);
336         le_conn = std::move(result).value();
337       },
338       bt::gap::LowEnergyConnectionOptions());
339   RunLoopUntilIdle();
340   ASSERT_TRUE(le_conn);
341   ASSERT_FALSE(
342       server()->FindConnectionForTesting(peer->identifier()).has_value());
343 
344   fuchsia::bluetooth::Status status;
345   auto callback = [&status](::fuchsia::bluetooth::Status cb_status) {
346     status = std::move(cb_status);
347   };
348 
349   fble::ConnectionOptions options;
350   fidl::InterfaceHandle<fuchsia::bluetooth::gatt::Client> gatt_client;
351   fidl::InterfaceRequest<fuchsia::bluetooth::gatt::Client> gatt_client_req =
352       gatt_client.NewRequest();
353   central_proxy()->ConnectPeripheral(peer->identifier().ToString(),
354                                      std::move(options),
355                                      std::move(gatt_client_req),
356                                      callback);
357   RunLoopUntilIdle();
358   EXPECT_EQ(status.error, nullptr);
359   auto server_conn = server()->FindConnectionForTesting(peer->identifier());
360   ASSERT_TRUE(server_conn.has_value());
361   EXPECT_NE(server_conn.value(), nullptr);
362 }
363 
TEST_F(LowEnergyCentralServerTest,ConnectPeripheralUnknownPeer)364 TEST_F(LowEnergyCentralServerTest, ConnectPeripheralUnknownPeer) {
365   fuchsia::bluetooth::Status status;
366   auto callback = [&status](::fuchsia::bluetooth::Status cb_status) {
367     status = std::move(cb_status);
368   };
369 
370   const bt::PeerId peer_id(1);
371 
372   fble::ConnectionOptions options;
373   fidl::InterfaceHandle<fuchsia::bluetooth::gatt::Client> gatt_client;
374   fidl::InterfaceRequest<fuchsia::bluetooth::gatt::Client> gatt_client_req =
375       gatt_client.NewRequest();
376   central_proxy()->ConnectPeripheral(peer_id.ToString(),
377                                      std::move(options),
378                                      std::move(gatt_client_req),
379                                      callback);
380   RunLoopUntilIdle();
381   ASSERT_TRUE(status.error);
382   EXPECT_EQ(status.error->error_code, fuchsia::bluetooth::ErrorCode::NOT_FOUND);
383   auto server_conn = server()->FindConnectionForTesting(peer_id);
384   EXPECT_FALSE(server_conn.has_value());
385 }
386 
TEST_F(LowEnergyCentralServerTest,DisconnectPeripheralClosesCorrectGattHandle)387 TEST_F(LowEnergyCentralServerTest,
388        DisconnectPeripheralClosesCorrectGattHandle) {
389   const bt::DeviceAddress kAddr1 = kTestAddr;
390   const bt::DeviceAddress kAddr2(bt::DeviceAddress::Type::kLEPublic,
391                                  {2, 0, 0, 0, 0, 0});
392   auto* const peer1 =
393       adapter()->peer_cache()->NewPeer(kAddr1, /*connectable=*/true);
394   auto* const peer2 =
395       adapter()->peer_cache()->NewPeer(kAddr2, /*connectable=*/true);
396 
397   test_device()->AddPeer(
398       std::make_unique<bt::testing::FakePeer>(kAddr1, pw_dispatcher()));
399   test_device()->AddPeer(
400       std::make_unique<bt::testing::FakePeer>(kAddr2, pw_dispatcher()));
401 
402   // Establish two connections.
403   fidl::InterfaceHandle<fgatt::Client> handle1, handle2;
404   central_proxy()->ConnectPeripheral(peer1->identifier().ToString(),
405                                      fble::ConnectionOptions{},
406                                      handle1.NewRequest(),
407                                      [](auto) {});
408   central_proxy()->ConnectPeripheral(peer2->identifier().ToString(),
409                                      fble::ConnectionOptions{},
410                                      handle2.NewRequest(),
411                                      [](auto) {});
412   RunLoopUntilIdle();
413   ASSERT_TRUE(server()->FindConnectionForTesting(peer1->identifier()));
414   ASSERT_TRUE(server()->FindConnectionForTesting(peer2->identifier()));
415   EXPECT_FALSE(IsClientHandleClosedAfterLoop(&handle1));
416   EXPECT_FALSE(IsClientHandleClosedAfterLoop(&handle2));
417 
418   // Disconnect peer1. Only its gatt.Client handle should close.
419   central_proxy()->DisconnectPeripheral(peer1->identifier().ToString(),
420                                         [](auto) {});
421   EXPECT_TRUE(IsClientHandleClosedAfterLoop(&handle1));
422   EXPECT_FALSE(IsClientHandleClosedAfterLoop(&handle2));
423 
424   // Disconnect peer2. Its handle should close now.
425   central_proxy()->DisconnectPeripheral(peer2->identifier().ToString(),
426                                         [](auto) {});
427   EXPECT_TRUE(IsClientHandleClosedAfterLoop(&handle2));
428 }
429 
TEST_F(LowEnergyCentralServerTest,PeerDisconnectClosesCorrectHandle)430 TEST_F(LowEnergyCentralServerTest, PeerDisconnectClosesCorrectHandle) {
431   const bt::DeviceAddress kAddr1 = kTestAddr;
432   const bt::DeviceAddress kAddr2(bt::DeviceAddress::Type::kLEPublic,
433                                  {2, 0, 0, 0, 0, 0});
434   auto* const peer1 =
435       adapter()->peer_cache()->NewPeer(kAddr1, /*connectable=*/true);
436   auto* const peer2 =
437       adapter()->peer_cache()->NewPeer(kAddr2, /*connectable=*/true);
438 
439   test_device()->AddPeer(
440       std::make_unique<bt::testing::FakePeer>(kAddr1, pw_dispatcher()));
441   test_device()->AddPeer(
442       std::make_unique<bt::testing::FakePeer>(kAddr2, pw_dispatcher()));
443 
444   // Establish two connections.
445   fidl::InterfaceHandle<fgatt::Client> handle1, handle2;
446   central_proxy()->ConnectPeripheral(peer1->identifier().ToString(),
447                                      fble::ConnectionOptions{},
448                                      handle1.NewRequest(),
449                                      [](auto) {});
450   central_proxy()->ConnectPeripheral(peer2->identifier().ToString(),
451                                      fble::ConnectionOptions{},
452                                      handle2.NewRequest(),
453                                      [](auto) {});
454   RunLoopUntilIdle();
455   ASSERT_TRUE(server()->FindConnectionForTesting(peer1->identifier()));
456   ASSERT_TRUE(server()->FindConnectionForTesting(peer2->identifier()));
457   EXPECT_FALSE(IsClientHandleClosedAfterLoop(&handle1));
458   EXPECT_FALSE(IsClientHandleClosedAfterLoop(&handle2));
459 
460   // Disconnect peer1. Only its gatt.Client handle should close.
461   test_device()->Disconnect(kAddr1);
462   EXPECT_TRUE(IsClientHandleClosedAfterLoop(&handle1));
463   EXPECT_FALSE(IsClientHandleClosedAfterLoop(&handle2));
464 
465   // Disconnect peer2. Its handle should close now.
466   test_device()->Disconnect(kAddr2);
467   EXPECT_TRUE(IsClientHandleClosedAfterLoop(&handle2));
468 }
469 
TEST_F(LowEnergyCentralServerTest,ClosingCentralHandleClosesAssociatedGattClientHandles)470 TEST_F(LowEnergyCentralServerTest,
471        ClosingCentralHandleClosesAssociatedGattClientHandles) {
472   const bt::DeviceAddress kAddr1 = kTestAddr;
473   const bt::DeviceAddress kAddr2(bt::DeviceAddress::Type::kLEPublic,
474                                  {2, 0, 0, 0, 0, 0});
475   auto* const peer1 =
476       adapter()->peer_cache()->NewPeer(kAddr1, /*connectable=*/true);
477   auto* const peer2 =
478       adapter()->peer_cache()->NewPeer(kAddr2, /*connectable=*/true);
479 
480   test_device()->AddPeer(
481       std::make_unique<bt::testing::FakePeer>(kAddr1, pw_dispatcher()));
482   test_device()->AddPeer(
483       std::make_unique<bt::testing::FakePeer>(kAddr2, pw_dispatcher()));
484 
485   // Establish two connections.
486   fidl::InterfaceHandle<fgatt::Client> handle1, handle2;
487   central_proxy()->ConnectPeripheral(peer1->identifier().ToString(),
488                                      fble::ConnectionOptions{},
489                                      handle1.NewRequest(),
490                                      [](auto) {});
491   central_proxy()->ConnectPeripheral(peer2->identifier().ToString(),
492                                      fble::ConnectionOptions{},
493                                      handle2.NewRequest(),
494                                      [](auto) {});
495   RunLoopUntilIdle();
496   ASSERT_TRUE(server()->FindConnectionForTesting(peer1->identifier()));
497   ASSERT_TRUE(server()->FindConnectionForTesting(peer2->identifier()));
498   EXPECT_FALSE(IsClientHandleClosedAfterLoop(&handle1));
499   EXPECT_FALSE(IsClientHandleClosedAfterLoop(&handle2));
500 
501   DestroyServer();
502   EXPECT_TRUE(IsClientHandleClosedAfterLoop(&handle1));
503   EXPECT_TRUE(IsClientHandleClosedAfterLoop(&handle2));
504 }
505 
TEST_F(LowEnergyCentralServerTest,ScanWithEmptyScanOptionsFails)506 TEST_F(LowEnergyCentralServerTest, ScanWithEmptyScanOptionsFails) {
507   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
508   auto result_watcher_server = result_watcher_handle.NewRequest();
509 
510   auto result_watcher_client = result_watcher_handle.Bind();
511   std::optional<zx_status_t> result_watcher_epitaph;
512   result_watcher_client.set_error_handler(
513       [&](zx_status_t epitaph) { result_watcher_epitaph = epitaph; });
514 
515   bool scan_stopped = false;
516   central_proxy()->Scan(fble::ScanOptions(),
517                         std::move(result_watcher_server),
518                         [&]() { scan_stopped = true; });
519   RunLoopUntilIdle();
520   EXPECT_TRUE(scan_stopped);
521   ASSERT_TRUE(result_watcher_epitaph.has_value());
522   EXPECT_EQ(result_watcher_epitaph.value(), ZX_ERR_INVALID_ARGS);
523 }
524 
TEST_F(LowEnergyCentralServerTest,ScanWithNoFiltersFails)525 TEST_F(LowEnergyCentralServerTest, ScanWithNoFiltersFails) {
526   fble::ScanOptions options;
527   std::vector<fble::Filter> filters;
528   options.set_filters(std::move(filters));
529 
530   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
531   auto result_watcher_server = result_watcher_handle.NewRequest();
532 
533   auto result_watcher_client = result_watcher_handle.Bind();
534   std::optional<zx_status_t> result_watcher_epitaph;
535   result_watcher_client.set_error_handler(
536       [&](zx_status_t epitaph) { result_watcher_epitaph = epitaph; });
537 
538   bool scan_stopped = false;
539   central_proxy()->Scan(std::move(options),
540                         std::move(result_watcher_server),
541                         [&]() { scan_stopped = true; });
542   RunLoopUntilIdle();
543   EXPECT_TRUE(scan_stopped);
544   ASSERT_TRUE(result_watcher_epitaph.has_value());
545   EXPECT_EQ(result_watcher_epitaph.value(), ZX_ERR_INVALID_ARGS);
546 }
547 
TEST_F(LowEnergyCentralServerTest,ScanReceivesPeerPreviouslyAddedToPeerCache)548 TEST_F(LowEnergyCentralServerTest, ScanReceivesPeerPreviouslyAddedToPeerCache) {
549   bt::gap::Peer* peer =
550       adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/false);
551 
552   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
553   auto result_watcher_server = result_watcher_handle.NewRequest();
554   auto result_watcher_client = result_watcher_handle.Bind();
555   std::optional<zx_status_t> epitaph;
556   result_watcher_client.set_error_handler(
557       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
558 
559   bool scan_stopped = false;
560   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
561                         std::move(result_watcher_server),
562                         [&]() { scan_stopped = true; });
563 
564   RunLoopUntilIdle();
565   EXPECT_FALSE(scan_stopped);
566   EXPECT_FALSE(epitaph);
567 
568   std::optional<std::vector<fble::Peer>> peers;
569   result_watcher_client->Watch(
570       [&](std::vector<fble::Peer> updated) { peers = std::move(updated); });
571   RunLoopUntilIdle();
572   ASSERT_TRUE(peers.has_value());
573   ASSERT_EQ(peers->size(), 1u);
574   ASSERT_TRUE(peers->front().has_id());
575   EXPECT_EQ(peers->front().id().value, peer->identifier().value());
576 
577   result_watcher_client.Unbind();
578   RunLoopUntilIdle();
579   EXPECT_TRUE(scan_stopped);
580 }
581 
TEST_F(LowEnergyCentralServerTest,ScanReceivesPeerAddedToPeerCacheAfterScanStart)582 TEST_F(LowEnergyCentralServerTest,
583        ScanReceivesPeerAddedToPeerCacheAfterScanStart) {
584   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
585   auto result_watcher_server = result_watcher_handle.NewRequest();
586   auto result_watcher_client = result_watcher_handle.Bind();
587   std::optional<zx_status_t> epitaph;
588   result_watcher_client.set_error_handler(
589       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
590 
591   bool scan_stopped = false;
592   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
593                         std::move(result_watcher_server),
594                         [&]() { scan_stopped = true; });
595 
596   RunLoopUntilIdle();
597   EXPECT_FALSE(scan_stopped);
598   EXPECT_FALSE(epitaph);
599 
600   std::optional<std::vector<fble::Peer>> peers;
601   result_watcher_client->Watch(
602       [&](std::vector<fble::Peer> updated) { peers = std::move(updated); });
603   RunLoopUntilIdle();
604   ASSERT_FALSE(peers.has_value());
605 
606   bt::gap::Peer* peer =
607       adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/false);
608   RunLoopUntilIdle();
609   ASSERT_TRUE(peers.has_value());
610   ASSERT_EQ(peers->size(), 1u);
611   ASSERT_TRUE(peers->front().has_id());
612   EXPECT_EQ(peers->front().id().value, peer->identifier().value());
613 
614   result_watcher_client.Unbind();
615   RunLoopUntilIdle();
616   EXPECT_TRUE(scan_stopped);
617 }
618 
TEST_F(LowEnergyCentralServerTest,PeerAddedToPeerCacheAfterScanEndDoesNotCrash)619 TEST_F(LowEnergyCentralServerTest,
620        PeerAddedToPeerCacheAfterScanEndDoesNotCrash) {
621   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
622   auto result_watcher_server = result_watcher_handle.NewRequest();
623   auto result_watcher_client = result_watcher_handle.Bind();
624   std::optional<zx_status_t> epitaph;
625   result_watcher_client.set_error_handler(
626       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
627 
628   bool scan_stopped = false;
629   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
630                         std::move(result_watcher_server),
631                         [&]() { scan_stopped = true; });
632 
633   RunLoopUntilIdle();
634   EXPECT_FALSE(scan_stopped);
635   EXPECT_FALSE(epitaph);
636 
637   RunLoopUntilIdle();
638 
639   result_watcher_client.Unbind();
640   RunLoopUntilIdle();
641   EXPECT_TRUE(scan_stopped);
642 
643   adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/false);
644   RunLoopUntilIdle();
645 }
646 
TEST_F(LowEnergyCentralServerTest,ConcurrentScansFail)647 TEST_F(LowEnergyCentralServerTest, ConcurrentScansFail) {
648   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle_0;
649   auto result_watcher_server_0 = result_watcher_handle_0.NewRequest();
650   auto result_watcher_client_0 = result_watcher_handle_0.Bind();
651   bool scan_stopped_0 = false;
652   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
653                         std::move(result_watcher_server_0),
654                         [&]() { scan_stopped_0 = true; });
655   RunLoopUntilIdle();
656   EXPECT_FALSE(scan_stopped_0);
657 
658   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle_1;
659   auto result_watcher_server_1 = result_watcher_handle_1.NewRequest();
660   auto result_watcher_client_1 = result_watcher_handle_1.Bind();
661   std::optional<zx_status_t> epitaph_1;
662   result_watcher_client_1.set_error_handler(
663       [&](zx_status_t cb_epitaph) { epitaph_1 = cb_epitaph; });
664 
665   bool scan_stopped_1 = false;
666   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
667                         std::move(result_watcher_server_1),
668                         [&]() { scan_stopped_1 = true; });
669   RunLoopUntilIdle();
670   EXPECT_FALSE(scan_stopped_0);
671   EXPECT_TRUE(scan_stopped_1);
672   ASSERT_TRUE(epitaph_1);
673   EXPECT_EQ(epitaph_1.value(), ZX_ERR_ALREADY_EXISTS);
674 
675   result_watcher_client_0.Unbind();
676   RunLoopUntilIdle();
677   EXPECT_TRUE(scan_stopped_0);
678 }
679 
TEST_F(LowEnergyCentralServerTest,SequentialScansSucceed)680 TEST_F(LowEnergyCentralServerTest, SequentialScansSucceed) {
681   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle_0;
682   auto result_watcher_server_0 = result_watcher_handle_0.NewRequest();
683   auto result_watcher_client_0 = result_watcher_handle_0.Bind();
684   bool scan_stopped_0 = false;
685   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
686                         std::move(result_watcher_server_0),
687                         [&]() { scan_stopped_0 = true; });
688   RunLoopUntilIdle();
689   EXPECT_FALSE(scan_stopped_0);
690 
691   result_watcher_client_0.Unbind();
692   RunLoopUntilIdle();
693   EXPECT_TRUE(scan_stopped_0);
694 
695   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle_1;
696   auto result_watcher_server_1 = result_watcher_handle_1.NewRequest();
697   auto result_watcher_client_1 = result_watcher_handle_1.Bind();
698   bool scan_stopped_1 = false;
699   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
700                         std::move(result_watcher_server_1),
701                         [&]() { scan_stopped_1 = true; });
702   RunLoopUntilIdle();
703   EXPECT_FALSE(scan_stopped_1);
704 
705   result_watcher_client_1.Unbind();
706   RunLoopUntilIdle();
707   EXPECT_TRUE(scan_stopped_1);
708 }
709 
TEST_F(LowEnergyCentralServerTest,IgnorePeersThatDoNotMatchFilter)710 TEST_F(LowEnergyCentralServerTest, IgnorePeersThatDoNotMatchFilter) {
711   fble::ScanOptions options;
712   fble::Filter filter;
713   filter.set_connectable(true);
714   std::vector<fble::Filter> filters;
715   filters.emplace_back(std::move(filter));
716   options.set_filters(std::move(filters));
717 
718   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
719   auto result_watcher_server = result_watcher_handle.NewRequest();
720   auto result_watcher_client = result_watcher_handle.Bind();
721   std::optional<zx_status_t> epitaph;
722   result_watcher_client.set_error_handler(
723       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
724 
725   bool scan_stopped = false;
726   central_proxy()->Scan(std::move(options),
727                         std::move(result_watcher_server),
728                         [&]() { scan_stopped = true; });
729 
730   RunLoopUntilIdle();
731   EXPECT_FALSE(scan_stopped);
732   EXPECT_FALSE(epitaph);
733 
734   std::optional<std::vector<fble::Peer>> peers;
735   result_watcher_client->Watch(
736       [&](std::vector<fble::Peer> updated) { peers = std::move(updated); });
737   RunLoopUntilIdle();
738   ASSERT_FALSE(peers.has_value());
739 
740   // Peer is not LE
741   adapter()->peer_cache()->NewPeer(
742       bt::DeviceAddress(bt::DeviceAddress::Type::kBREDR, {1, 0, 0, 0, 0, 0}),
743       /*connectable=*/true);
744   // Peer is not connectable
745   adapter()->peer_cache()->NewPeer(
746       bt::DeviceAddress(bt::DeviceAddress::Type::kLEPublic, {2, 0, 0, 0, 0, 0}),
747       /*connectable=*/false);
748 
749   RunLoopUntilIdle();
750   EXPECT_FALSE(peers.has_value());
751 
752   result_watcher_client.Unbind();
753   RunLoopUntilIdle();
754   EXPECT_TRUE(scan_stopped);
755 }
756 
TEST_F(LowEnergyCentralServerTest,IgnorePeerThatDoesNotMatchServiceDataFilter)757 TEST_F(LowEnergyCentralServerTest,
758        IgnorePeerThatDoesNotMatchServiceDataFilter) {
759   fble::ScanOptions options;
760   fble::Filter filter;
761   const bt::UUID kServiceUuid(static_cast<uint16_t>(2));
762   filter.set_connectable(true);
763   filter.set_service_data_uuid(fuchsia::bluetooth::Uuid{kServiceUuid.value()});
764   std::vector<fble::Filter> filters;
765   filters.emplace_back(std::move(filter));
766   options.set_filters(std::move(filters));
767 
768   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
769   auto result_watcher_server = result_watcher_handle.NewRequest();
770   auto result_watcher_client = result_watcher_handle.Bind();
771   std::optional<zx_status_t> epitaph;
772   result_watcher_client.set_error_handler(
773       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
774 
775   bool scan_stopped = false;
776   central_proxy()->Scan(std::move(options),
777                         std::move(result_watcher_server),
778                         [&]() { scan_stopped = true; });
779 
780   RunLoopUntilIdle();
781   EXPECT_FALSE(scan_stopped);
782   EXPECT_FALSE(epitaph);
783 
784   std::optional<std::vector<fble::Peer>> peers;
785   result_watcher_client->Watch(
786       [&](std::vector<fble::Peer> updated) { peers = std::move(updated); });
787   RunLoopUntilIdle();
788   ASSERT_FALSE(peers.has_value());
789 
790   // Peer is connectable but doesn't have any service data.
791   adapter()->peer_cache()->NewPeer(
792       bt::DeviceAddress(bt::DeviceAddress::Type::kLEPublic, {2, 0, 0, 0, 0, 0}),
793       /*connectable=*/true);
794 
795   RunLoopUntilIdle();
796   EXPECT_FALSE(peers.has_value());
797 
798   result_watcher_client.Unbind();
799   RunLoopUntilIdle();
800   EXPECT_TRUE(scan_stopped);
801 }
802 
TEST_F(LowEnergyCentralServerTest,DoNotNotifyResultWatcherWithPeerThatWasRemovedFromPeerCacheWhileQueued)803 TEST_F(LowEnergyCentralServerTest,
804        DoNotNotifyResultWatcherWithPeerThatWasRemovedFromPeerCacheWhileQueued) {
805   bt::gap::Peer* peer =
806       adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/false);
807 
808   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
809   auto result_watcher_server = result_watcher_handle.NewRequest();
810   auto result_watcher_client = result_watcher_handle.Bind();
811   std::optional<zx_status_t> epitaph;
812   result_watcher_client.set_error_handler(
813       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
814 
815   bool scan_stopped = false;
816   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
817                         std::move(result_watcher_server),
818                         [&]() { scan_stopped = true; });
819 
820   RunLoopUntilIdle();
821   EXPECT_FALSE(scan_stopped);
822   EXPECT_FALSE(epitaph);
823 
824   // Peer is in ScanResultWatcher queue. Remove it from PeerCache before Watch()
825   // is called.
826   EXPECT_TRUE(
827       adapter()->peer_cache()->RemoveDisconnectedPeer(peer->identifier()));
828 
829   std::optional<std::vector<fble::Peer>> peers;
830   result_watcher_client->Watch(
831       [&](std::vector<fble::Peer> updated) { peers = std::move(updated); });
832   RunLoopUntilIdle();
833   EXPECT_FALSE(peers.has_value());
834 
835   result_watcher_client.Unbind();
836   RunLoopUntilIdle();
837   EXPECT_TRUE(scan_stopped);
838 }
839 
TEST_F(LowEnergyCentralServerTest,MaxQueuedScanResultWatcherPeers)840 TEST_F(LowEnergyCentralServerTest, MaxQueuedScanResultWatcherPeers) {
841   // Create smallest possible peer
842   bt::gap::Peer* peer_0 = adapter()->peer_cache()->NewPeer(
843       bt::DeviceAddress(bt::DeviceAddress::Type::kLEPublic, {0, 0, 0, 0, 0, 0}),
844       /*connectable=*/false);
845   const size_t kMaxPeersPerChannel =
846       MaxPeersPerScanResultWatcherChannel(*peer_0);
847   ASSERT_GT(kMaxPeersPerChannel,
848             LowEnergyCentralServer::kMaxPendingScanResultWatcherPeers);
849 
850   // Queue 1 more peer than queue size limit.
851   ASSERT_LE(LowEnergyCentralServer::kMaxPendingScanResultWatcherPeers,
852             std::numeric_limits<uint8_t>::max());
853   for (size_t i = 1;
854        i < LowEnergyCentralServer::kMaxPendingScanResultWatcherPeers + 1;
855        i++) {
856     SCOPED_TRACE(i);
857     ASSERT_TRUE(adapter()->peer_cache()->NewPeer(
858         bt::DeviceAddress(bt::DeviceAddress::Type::kLEPublic,
859                           {static_cast<uint8_t>(i), 0, 0, 0, 0, 0}),
860         /*connectable=*/false));
861   }
862 
863   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
864   auto result_watcher_server = result_watcher_handle.NewRequest();
865   auto result_watcher_client = result_watcher_handle.Bind();
866   std::optional<zx_status_t> epitaph;
867   result_watcher_client.set_error_handler(
868       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
869 
870   bool scan_stopped = false;
871   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
872                         std::move(result_watcher_server),
873                         [&]() { scan_stopped = true; });
874 
875   RunLoopUntilIdle();
876   EXPECT_FALSE(scan_stopped);
877   EXPECT_FALSE(epitaph);
878 
879   std::optional<std::vector<fble::Peer>> peers;
880   result_watcher_client->Watch(
881       [&](std::vector<fble::Peer> updated) { peers = std::move(updated); });
882   RunLoopUntilIdle();
883   ASSERT_TRUE(peers.has_value());
884   EXPECT_EQ(peers->size(),
885             LowEnergyCentralServer::kMaxPendingScanResultWatcherPeers);
886   peers.reset();
887 
888   // Additional calls to Watch should hang
889   result_watcher_client->Watch(
890       [&](std::vector<fble::Peer> updated) { peers = std::move(updated); });
891   RunLoopUntilIdle();
892   EXPECT_FALSE(peers.has_value());
893 
894   result_watcher_client.Unbind();
895   RunLoopUntilIdle();
896   EXPECT_TRUE(scan_stopped);
897 }
898 
TEST_F(LowEnergyCentralServerTest,ScanResultWatcherMeasureTape)899 TEST_F(LowEnergyCentralServerTest, ScanResultWatcherMeasureTape) {
900   // Create a very large Peer
901   bt::gap::Peer* peer_0 = adapter()->peer_cache()->NewPeer(
902       bt::DeviceAddress(bt::DeviceAddress::Type::kLEPublic, {0, 0, 0, 0, 0, 0}),
903       /*connectable=*/true);
904   bt::AdvertisingData adv_data;
905   for (int i = 0; i < 100; i++) {
906     SCOPED_TRACE(i);
907     ASSERT_TRUE(adv_data.AddUri(
908         bt_lib_cpp_string::StringPrintf("uri:a-really-long-uri-%d", i)));
909   }
910   adv_data.CalculateBlockSize();
911   bt::DynamicByteBuffer adv_buffer(adv_data.CalculateBlockSize());
912   adv_data.WriteBlock(&adv_buffer, std::nullopt);
913   peer_0->MutLe().SetAdvertisingData(
914       /*rssi=*/0, adv_buffer, pw::chrono::SystemClock::time_point());
915 
916   const size_t kMaxPeersPerChannel =
917       MaxPeersPerScanResultWatcherChannel(*peer_0);
918 
919   // Queue 1 more peer than will fit in the channel.
920   // Start at i = 1 because peer_0 was created above.
921   ASSERT_LE(kMaxPeersPerChannel, std::numeric_limits<uint8_t>::max());
922   ASSERT_GT(LowEnergyCentralServer::kMaxPendingScanResultWatcherPeers,
923             kMaxPeersPerChannel);
924   for (size_t i = 1; i < kMaxPeersPerChannel + 1; i++) {
925     SCOPED_TRACE(i);
926     bt::gap::Peer* peer = adapter()->peer_cache()->NewPeer(
927         bt::DeviceAddress(bt::DeviceAddress::Type::kLEPublic,
928                           {static_cast<uint8_t>(i), 0, 0, 0, 0, 0}),
929         /*connectable=*/false);
930     ASSERT_TRUE(peer);
931     peer->MutLe().SetAdvertisingData(
932         /*rssi=*/0, adv_buffer, pw::chrono::SystemClock::time_point());
933   }
934 
935   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
936   auto result_watcher_server = result_watcher_handle.NewRequest();
937   auto result_watcher_client = result_watcher_handle.Bind();
938   std::optional<zx_status_t> epitaph;
939   result_watcher_client.set_error_handler(
940       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
941 
942   bool scan_stopped = false;
943   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
944                         std::move(result_watcher_server),
945                         [&]() { scan_stopped = true; });
946 
947   RunLoopUntilIdle();
948   EXPECT_FALSE(scan_stopped);
949   EXPECT_FALSE(epitaph);
950 
951   std::optional<std::vector<fble::Peer>> peers;
952   result_watcher_client->Watch(
953       [&](std::vector<fble::Peer> updated) { peers = std::move(updated); });
954   RunLoopUntilIdle();
955   ASSERT_TRUE(peers.has_value());
956   EXPECT_EQ(peers->size(), kMaxPeersPerChannel);
957   peers.reset();
958 
959   // Additional call to Watch should return the 1 peer that exceeded the channel
960   // size limit.
961   result_watcher_client->Watch(
962       [&](std::vector<fble::Peer> updated) { peers = std::move(updated); });
963   RunLoopUntilIdle();
964   ASSERT_TRUE(peers.has_value());
965   EXPECT_EQ(peers->size(), 1u);
966 
967   result_watcher_client.Unbind();
968   RunLoopUntilIdle();
969   EXPECT_TRUE(scan_stopped);
970 }
971 
TEST_F(LowEnergyCentralServerTest,ScanResultsMatchPeerFromAnyFilter)972 TEST_F(LowEnergyCentralServerTest, ScanResultsMatchPeerFromAnyFilter) {
973   const int8_t kRssi = 0;
974   // Peer that matches neither filter
975   adapter()->peer_cache()->NewPeer(
976       bt::DeviceAddress(bt::DeviceAddress::Type::kLEPublic, {0, 0, 0, 0, 0, 0}),
977       /*connectable=*/false);
978 
979   // Peer that matches filter_0
980   bt::gap::Peer* peer_0 = adapter()->peer_cache()->NewPeer(
981       bt::DeviceAddress(bt::DeviceAddress::Type::kLEPublic, {1, 0, 0, 0, 0, 0}),
982       /*connectable=*/true);
983   ASSERT_TRUE(peer_0);
984   const auto kAdvData0 =
985       bt::StaticByteBuffer(0x02,  // Length
986                            0x09,  // AD type: Complete Local Name
987                            '0');
988   peer_0->MutLe().SetAdvertisingData(
989       kRssi, kAdvData0, pw::chrono::SystemClock::time_point());
990   // Peer that matches filter_1
991   bt::gap::Peer* peer_1 = adapter()->peer_cache()->NewPeer(
992       bt::DeviceAddress(bt::DeviceAddress::Type::kLEPublic, {2, 0, 0, 0, 0, 0}),
993       /*connectable=*/false);
994   ASSERT_TRUE(peer_1);
995   const auto kAdvData1 =
996       bt::StaticByteBuffer(0x02,  // Length
997                            0x09,  // AD type: Complete Local Name
998                            '1');
999   peer_1->MutLe().SetAdvertisingData(
1000       kRssi, kAdvData1, pw::chrono::SystemClock::time_point());
1001 
1002   fble::ScanOptions options;
1003   fble::Filter filter_0;
1004   filter_0.set_connectable(true);
1005   filter_0.set_name("0");
1006   fble::Filter filter_1;
1007   filter_1.set_connectable(false);
1008   filter_1.set_name("1");
1009   std::vector<fble::Filter> filters;
1010   filters.emplace_back(std::move(filter_0));
1011   filters.emplace_back(std::move(filter_1));
1012   options.set_filters(std::move(filters));
1013 
1014   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
1015   auto result_watcher_server = result_watcher_handle.NewRequest();
1016   auto result_watcher_client = result_watcher_handle.Bind();
1017   std::optional<zx_status_t> epitaph;
1018   result_watcher_client.set_error_handler(
1019       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
1020 
1021   bool scan_stopped = false;
1022   central_proxy()->Scan(std::move(options),
1023                         std::move(result_watcher_server),
1024                         [&]() { scan_stopped = true; });
1025 
1026   RunLoopUntilIdle();
1027   EXPECT_FALSE(scan_stopped);
1028   EXPECT_FALSE(epitaph);
1029 
1030   std::optional<std::vector<bt::PeerId>> peers;
1031   result_watcher_client->Watch([&](std::vector<fble::Peer> updated) {
1032     peers = std::vector<bt::PeerId>();
1033     std::transform(updated.begin(),
1034                    updated.end(),
1035                    std::back_inserter(*peers),
1036                    [](auto& p) { return bt::PeerId(p.id().value); });
1037   });
1038   RunLoopUntilIdle();
1039   ASSERT_TRUE(peers.has_value());
1040   EXPECT_THAT(
1041       peers.value(),
1042       ::testing::UnorderedElementsAre(::testing::Eq(peer_0->identifier()),
1043                                       ::testing::Eq(peer_1->identifier())));
1044   result_watcher_client.Unbind();
1045   RunLoopUntilIdle();
1046   EXPECT_TRUE(scan_stopped);
1047 }
1048 
TEST_F(LowEnergyCentralServerTest,DiscoveryStartJustAfterScanCanceledShouldBeIgnored)1049 TEST_F(LowEnergyCentralServerTest,
1050        DiscoveryStartJustAfterScanCanceledShouldBeIgnored) {
1051   // Pause discovery so that we can cancel scanning before resuming discovery.
1052   fit::closure start_discovery;
1053   test_device()->pause_responses_for_opcode(
1054       bt::hci_spec::kLESetScanEnable, [&](auto resume_set_scan_enable) {
1055         start_discovery = std::move(resume_set_scan_enable);
1056       });
1057 
1058   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
1059   auto result_watcher_server = result_watcher_handle.NewRequest();
1060   auto result_watcher_client = result_watcher_handle.Bind();
1061 
1062   bool scan_stopped = false;
1063   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
1064                         std::move(result_watcher_server),
1065                         [&]() { scan_stopped = true; });
1066 
1067   RunLoopUntilIdle();
1068   EXPECT_FALSE(scan_stopped);
1069   EXPECT_TRUE(start_discovery);
1070 
1071   result_watcher_client.Unbind();
1072   RunLoopUntilIdle();
1073   EXPECT_TRUE(scan_stopped);
1074 
1075   start_discovery();
1076   RunLoopUntilIdle();
1077 }
1078 
TEST_F(LowEnergyCentralServerTest,ScanFailsToStart)1079 TEST_F(LowEnergyCentralServerTest, ScanFailsToStart) {
1080   test_device()->SetDefaultResponseStatus(
1081       bt::hci_spec::kLESetScanEnable,
1082       pw::bluetooth::emboss::StatusCode::CONTROLLER_BUSY);
1083 
1084   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
1085   auto result_watcher_server = result_watcher_handle.NewRequest();
1086   auto result_watcher_client = result_watcher_handle.Bind();
1087   std::optional<zx_status_t> epitaph;
1088   result_watcher_client.set_error_handler(
1089       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
1090 
1091   bool scan_stopped = false;
1092   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
1093                         std::move(result_watcher_server),
1094                         [&]() { scan_stopped = true; });
1095 
1096   RunLoopUntilIdle();
1097   EXPECT_TRUE(scan_stopped);
1098   ASSERT_TRUE(epitaph);
1099   EXPECT_EQ(*epitaph, ZX_ERR_INTERNAL);
1100 }
1101 
TEST_F(LowEnergyCentralServerTest,ScanSessionErrorCancelsScan)1102 TEST_F(LowEnergyCentralServerTest, ScanSessionErrorCancelsScan) {
1103   zx::duration kTestScanPeriod = zx::sec(1);
1104   pw::chrono::SystemClock::duration kPwTestScanPeriod = std::chrono::seconds(1);
1105   adapter()->le()->set_scan_period_for_testing(kPwTestScanPeriod);
1106   std::vector<bool> scan_states;
1107   test_device()->set_scan_state_callback([&](bool enabled) {
1108     scan_states.push_back(enabled);
1109     // Wait for 2 state transitions: -> enabled -> disabled.
1110     // Then disable restarting scanning, so that an error is sent to sessions.
1111     if (scan_states.size() == 2u) {
1112       EXPECT_FALSE(enabled);
1113       test_device()->SetDefaultResponseStatus(
1114           bt::hci_spec::kLESetScanEnable,
1115           pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
1116     }
1117   });
1118 
1119   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
1120   auto result_watcher_server = result_watcher_handle.NewRequest();
1121   auto result_watcher_client = result_watcher_handle.Bind();
1122   std::optional<zx_status_t> epitaph;
1123   result_watcher_client.set_error_handler(
1124       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
1125 
1126   bool scan_stopped = false;
1127   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
1128                         std::move(result_watcher_server),
1129                         [&]() { scan_stopped = true; });
1130   RunLoopFor(kTestScanPeriod);
1131   EXPECT_TRUE(scan_stopped);
1132   ASSERT_TRUE(epitaph);
1133   EXPECT_EQ(*epitaph, ZX_ERR_INTERNAL);
1134 }
1135 
TEST_F(LowEnergyCentralServerTest,ScanResultWatcherWatchCalledBeforePreviousWatchReceivedResponse)1136 TEST_F(LowEnergyCentralServerTest,
1137        ScanResultWatcherWatchCalledBeforePreviousWatchReceivedResponse) {
1138   fidl::InterfaceHandle<fble::ScanResultWatcher> result_watcher_handle;
1139   auto result_watcher_server = result_watcher_handle.NewRequest();
1140   auto result_watcher_client = result_watcher_handle.Bind();
1141   std::optional<zx_status_t> epitaph;
1142   result_watcher_client.set_error_handler(
1143       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
1144 
1145   bool scan_stopped = false;
1146   central_proxy()->Scan(ScanOptionsWithEmptyFilter(),
1147                         std::move(result_watcher_server),
1148                         [&]() { scan_stopped = true; });
1149   bool watch_response_0 = false;
1150   result_watcher_client->Watch([&](auto) { watch_response_0 = true; });
1151   bool watch_response_1 = false;
1152   result_watcher_client->Watch([&](auto) { watch_response_1 = true; });
1153   RunLoopUntilIdle();
1154   EXPECT_FALSE(watch_response_0);
1155   EXPECT_FALSE(watch_response_1);
1156   EXPECT_TRUE(scan_stopped);
1157   ASSERT_TRUE(epitaph);
1158   EXPECT_EQ(*epitaph, ZX_ERR_CANCELED);
1159 }
1160 
TEST_F(LowEnergyCentralServerTest,ConnectToAlreadyConnectedPeerFails)1161 TEST_F(LowEnergyCentralServerTest, ConnectToAlreadyConnectedPeerFails) {
1162   auto* const peer =
1163       adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/true);
1164   ASSERT_TRUE(peer);
1165   test_device()->AddPeer(
1166       std::make_unique<bt::testing::FakePeer>(kTestAddr, pw_dispatcher()));
1167 
1168   fble::ConnectionPtr conn_client_0;
1169   std::optional<zx_status_t> epitaph_0;
1170   conn_client_0.set_error_handler(
1171       [&](zx_status_t cb_epitaph) { epitaph_0 = cb_epitaph; });
1172 
1173   const fuchsia::bluetooth::PeerId peer_id{peer->identifier().value()};
1174   fble::ConnectionOptions options_0;
1175   central_proxy()->Connect(
1176       peer_id, std::move(options_0), conn_client_0.NewRequest());
1177   RunLoopUntilIdle();
1178   EXPECT_FALSE(epitaph_0.has_value());
1179 
1180   fble::ConnectionPtr conn_client_1;
1181   std::optional<zx_status_t> epitaph_1;
1182   conn_client_1.set_error_handler(
1183       [&](zx_status_t cb_epitaph) { epitaph_1 = cb_epitaph; });
1184 
1185   fble::ConnectionOptions options_1;
1186   central_proxy()->Connect(
1187       peer_id, std::move(options_1), conn_client_1.NewRequest());
1188   RunLoopUntilIdle();
1189   EXPECT_FALSE(epitaph_0.has_value());
1190   ASSERT_TRUE(epitaph_1.has_value());
1191   EXPECT_EQ(epitaph_1.value(), ZX_ERR_ALREADY_BOUND);
1192 }
1193 
TEST_F(LowEnergyCentralServerTest,ConnectToPeerWithRequestPending)1194 TEST_F(LowEnergyCentralServerTest, ConnectToPeerWithRequestPending) {
1195   auto* const peer =
1196       adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/true);
1197   ASSERT_TRUE(peer);
1198 
1199   auto fake_peer =
1200       std::make_unique<bt::testing::FakePeer>(kTestAddr, pw_dispatcher());
1201   fake_peer->force_pending_connect();
1202   test_device()->AddPeer(std::move(fake_peer));
1203 
1204   fble::ConnectionPtr conn_client_0;
1205   std::optional<zx_status_t> epitaph_0;
1206   conn_client_0.set_error_handler(
1207       [&](zx_status_t cb_epitaph) { epitaph_0 = cb_epitaph; });
1208 
1209   const fuchsia::bluetooth::PeerId peer_id{peer->identifier().value()};
1210   fble::ConnectionOptions options_0;
1211   central_proxy()->Connect(
1212       peer_id, std::move(options_0), conn_client_0.NewRequest());
1213   RunLoopUntilIdle();
1214   EXPECT_FALSE(epitaph_0.has_value());
1215 
1216   fble::ConnectionPtr conn_client_1;
1217   std::optional<zx_status_t> epitaph_1;
1218   conn_client_1.set_error_handler(
1219       [&](zx_status_t cb_epitaph) { epitaph_1 = cb_epitaph; });
1220 
1221   fble::ConnectionOptions options_1;
1222   central_proxy()->Connect(
1223       peer_id, std::move(options_1), conn_client_1.NewRequest());
1224   RunLoopUntilIdle();
1225   EXPECT_FALSE(epitaph_0.has_value());
1226   ASSERT_TRUE(epitaph_1.has_value());
1227   EXPECT_EQ(epitaph_1.value(), ZX_ERR_ALREADY_BOUND);
1228 }
1229 
TEST_F(LowEnergyCentralServerTest,ConnectToPeerAlreadyConnectedInLowEnergyConnectionManager)1230 TEST_F(LowEnergyCentralServerTest,
1231        ConnectToPeerAlreadyConnectedInLowEnergyConnectionManager) {
1232   auto* const peer =
1233       adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/true);
1234   ASSERT_TRUE(peer);
1235   test_device()->AddPeer(
1236       std::make_unique<bt::testing::FakePeer>(kTestAddr, pw_dispatcher()));
1237 
1238   std::unique_ptr<bt::gap::LowEnergyConnectionHandle> le_conn;
1239   adapter()->le()->Connect(
1240       peer->identifier(),
1241       [&le_conn](auto result) {
1242         ASSERT_EQ(fit::ok(), result);
1243         le_conn = std::move(result).value();
1244       },
1245       bt::gap::LowEnergyConnectionOptions());
1246   RunLoopUntilIdle();
1247   ASSERT_TRUE(le_conn);
1248 
1249   fble::ConnectionPtr conn_client1;
1250   std::optional<zx_status_t> epitaph1;
1251   conn_client1.set_error_handler(
1252       [&](zx_status_t cb_epitaph) { epitaph1 = cb_epitaph; });
1253 
1254   const fuchsia::bluetooth::PeerId kFidlPeerId{peer->identifier().value()};
1255   fble::ConnectionOptions options1;
1256   central_proxy()->Connect(
1257       kFidlPeerId, std::move(options1), conn_client1.NewRequest());
1258   RunLoopUntilIdle();
1259   EXPECT_FALSE(epitaph1.has_value());
1260 }
1261 
TEST_F(LowEnergyCentralServerTest,ConnectThenPeerDisconnectThenReconnect)1262 TEST_F(LowEnergyCentralServerTest, ConnectThenPeerDisconnectThenReconnect) {
1263   auto* const peer =
1264       adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/true);
1265   ASSERT_TRUE(peer);
1266   const fuchsia::bluetooth::PeerId kFidlPeerId{peer->identifier().value()};
1267 
1268   std::unique_ptr<bt::testing::FakePeer> fake_peer =
1269       std::make_unique<bt::testing::FakePeer>(kTestAddr, pw_dispatcher());
1270   test_device()->AddPeer(std::move(fake_peer));
1271 
1272   fble::ConnectionPtr conn_client_0;
1273   std::optional<zx_status_t> epitaph_0;
1274   conn_client_0.set_error_handler(
1275       [&](zx_status_t cb_epitaph) { epitaph_0 = cb_epitaph; });
1276 
1277   fble::ConnectionOptions options_0;
1278   central_proxy()->Connect(
1279       kFidlPeerId, std::move(options_0), conn_client_0.NewRequest());
1280   RunLoopUntilIdle();
1281   EXPECT_FALSE(epitaph_0.has_value());
1282 
1283   test_device()->Disconnect(kTestAddr);
1284   RunLoopUntilIdle();
1285   EXPECT_TRUE(epitaph_0.has_value());
1286 
1287   fble::ConnectionPtr conn_client_1;
1288   std::optional<zx_status_t> epitaph_1;
1289   conn_client_1.set_error_handler(
1290       [&](zx_status_t cb_epitaph) { epitaph_1 = cb_epitaph; });
1291 
1292   fble::ConnectionOptions options_1;
1293   central_proxy()->Connect(
1294       kFidlPeerId, std::move(options_1), conn_client_1.NewRequest());
1295   RunLoopUntilIdle();
1296   EXPECT_FALSE(epitaph_1.has_value());
1297 }
1298 
TEST_F(LowEnergyCentralServerTest,ConnectFailsDueToPeerNotConnectableThenConnectSuceeds)1299 TEST_F(LowEnergyCentralServerTest,
1300        ConnectFailsDueToPeerNotConnectableThenConnectSuceeds) {
1301   bt::gap::Peer* peer =
1302       adapter()->peer_cache()->NewPeer(kTestAddr, /*connectable=*/false);
1303   ASSERT_TRUE(peer);
1304   auto fake_peer =
1305       std::make_unique<bt::testing::FakePeer>(kTestAddr, pw_dispatcher());
1306   test_device()->AddPeer(std::move(fake_peer));
1307 
1308   fble::ConnectionPtr conn_client_0;
1309   std::optional<zx_status_t> epitaph_0;
1310   conn_client_0.set_error_handler(
1311       [&](zx_status_t cb_epitaph) { epitaph_0 = cb_epitaph; });
1312 
1313   central_proxy()->Connect(
1314       fuchsia::bluetooth::PeerId{peer->identifier().value()},
1315       fble::ConnectionOptions{},
1316       conn_client_0.NewRequest());
1317   RunLoopUntilIdle();
1318   ASSERT_TRUE(epitaph_0.has_value());
1319   EXPECT_EQ(epitaph_0.value(), ZX_ERR_NOT_CONNECTED);
1320 
1321   // Connect to peer to verify connection state was cleaned up on previous
1322   // error.
1323   peer->set_connectable(true);
1324 
1325   fble::ConnectionPtr conn_client_1;
1326   std::optional<zx_status_t> epitaph_1;
1327   conn_client_1.set_error_handler(
1328       [&](zx_status_t cb_epitaph) { epitaph_1 = cb_epitaph; });
1329 
1330   central_proxy()->Connect(
1331       fuchsia::bluetooth::PeerId{peer->identifier().value()},
1332       fble::ConnectionOptions{},
1333       conn_client_1.NewRequest());
1334   RunLoopUntilIdle();
1335   EXPECT_FALSE(epitaph_1.has_value());
1336 }
1337 
TEST_F(LowEnergyCentralServerTestFakeAdapter,ConnectWithConnectionOptionsNonBondableAndServiceFilter)1338 TEST_F(LowEnergyCentralServerTestFakeAdapter,
1339        ConnectWithConnectionOptionsNonBondableAndServiceFilter) {
1340   const bt::PeerId kPeerId(1);
1341   const bt::UUID kServiceUuid(static_cast<uint16_t>(2));
1342 
1343   fble::ConnectionPtr conn_client;
1344   std::optional<zx_status_t> epitaph;
1345   conn_client.set_error_handler(
1346       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
1347 
1348   fble::ConnectionOptions options;
1349   options.set_bondable_mode(false);
1350   options.set_service_filter(fuchsia::bluetooth::Uuid{kServiceUuid.value()});
1351   central_proxy()->Connect(fuchsia::bluetooth::PeerId{kPeerId.value()},
1352                            std::move(options),
1353                            conn_client.NewRequest());
1354   RunLoopUntilIdle();
1355   EXPECT_FALSE(epitaph.has_value());
1356 
1357   auto& connections = adapter()->fake_le()->connections();
1358   auto conn_iter = connections.find(kPeerId);
1359   ASSERT_NE(conn_iter, connections.end());
1360   EXPECT_EQ(conn_iter->second.options.bondable_mode,
1361             bt::sm::BondableMode::NonBondable);
1362   ASSERT_TRUE(conn_iter->second.options.service_uuid.has_value());
1363   EXPECT_EQ(conn_iter->second.options.service_uuid, kServiceUuid);
1364   EXPECT_EQ(conn_iter->second.options.auto_connect, false);
1365 }
1366 
TEST_P(LowEnergyCentralServerTestFakeAdapterBoolParam,ConnectConnectionOptionsBondable)1367 TEST_P(LowEnergyCentralServerTestFakeAdapterBoolParam,
1368        ConnectConnectionOptionsBondable) {
1369   const bt::PeerId kPeerId(1);
1370 
1371   fble::ConnectionPtr conn_client;
1372   std::optional<zx_status_t> epitaph;
1373   conn_client.set_error_handler(
1374       [&](zx_status_t cb_epitaph) { epitaph = cb_epitaph; });
1375 
1376   fble::ConnectionOptions options;
1377   // Bondable mode option defaults to true, so behavior shouldn't change whether
1378   // or not it is explicitly set to true.
1379   if (GetParam()) {
1380     options.set_bondable_mode(true);
1381   }
1382   central_proxy()->Connect(fuchsia::bluetooth::PeerId{kPeerId.value()},
1383                            std::move(options),
1384                            conn_client.NewRequest());
1385   RunLoopUntilIdle();
1386   EXPECT_FALSE(epitaph.has_value());
1387 
1388   auto& connections = adapter()->fake_le()->connections();
1389   auto conn_iter = connections.find(kPeerId);
1390   ASSERT_NE(conn_iter, connections.end());
1391   EXPECT_EQ(conn_iter->second.options.bondable_mode,
1392             bt::sm::BondableMode::Bondable);
1393 }
1394 
1395 INSTANTIATE_TEST_SUITE_P(LowEnergyCentralServerTestFakeAdapterBoolParamTests,
1396                          LowEnergyCentralServerTestFakeAdapterBoolParam,
1397                          ::testing::Bool());
1398 
1399 }  // namespace
1400 }  // namespace bthost
1401