• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/gap/low_energy_discovery_manager.h"
16 
17 #include <gmock/gmock.h>
18 #include <pw_assert/check.h>
19 
20 #include <unordered_set>
21 #include <vector>
22 
23 #include "pw_bluetooth_sapphire/internal/host/common/advertising_data.h"
24 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
25 #include "pw_bluetooth_sapphire/internal/host/gap/peer.h"
26 #include "pw_bluetooth_sapphire/internal/host/gap/peer_cache.h"
27 #include "pw_bluetooth_sapphire/internal/host/hci/discovery_filter.h"
28 #include "pw_bluetooth_sapphire/internal/host/hci/fake_local_address_delegate.h"
29 #include "pw_bluetooth_sapphire/internal/host/hci/legacy_low_energy_scanner.h"
30 #include "pw_bluetooth_sapphire/internal/host/hci/low_energy_scanner.h"
31 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
32 #include "pw_bluetooth_sapphire/internal/host/testing/fake_controller.h"
33 #include "pw_bluetooth_sapphire/internal/host/testing/fake_peer.h"
34 #include "pw_bluetooth_sapphire/internal/host/testing/inspect.h"
35 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
36 
37 namespace bt::gap {
38 namespace {
39 
40 using namespace inspect::testing;
41 using bt::testing::FakeController;
42 using bt::testing::FakePeer;
43 using PauseToken = LowEnergyDiscoveryManager::PauseToken;
44 
45 using TestingBase = bt::testing::FakeDispatcherControllerTest<FakeController>;
46 
47 const DeviceAddress kAddress0(DeviceAddress::Type::kLEPublic, {0});
48 const DeviceAddress kAddrAlias0(DeviceAddress::Type::kBREDR, kAddress0.value());
49 const DeviceAddress kAddress1(DeviceAddress::Type::kLERandom, {1});
50 const DeviceAddress kAddress2(DeviceAddress::Type::kLEPublic, {2});
51 const DeviceAddress kAddress3(DeviceAddress::Type::kLEPublic, {3});
52 const DeviceAddress kAddress4(DeviceAddress::Type::kLEPublic, {4});
53 const DeviceAddress kAddress5(DeviceAddress::Type::kLEPublic, {5});
54 
55 constexpr uint16_t kServiceDataUuid = 0x1234;
56 
57 constexpr pw::chrono::SystemClock::duration kTestScanPeriod =
58     std::chrono::seconds(10);
59 
60 const char* kInspectNodeName = "low_energy_discovery_manager";
61 
62 class LowEnergyDiscoveryManagerTest : public TestingBase {
63  public:
64   LowEnergyDiscoveryManagerTest() = default;
65   ~LowEnergyDiscoveryManagerTest() override = default;
66 
SetUp()67   void SetUp() override {
68     TestingBase::SetUp();
69 
70     scan_enabled_ = false;
71 
72     FakeController::Settings settings;
73     settings.ApplyLegacyLEConfig();
74     test_device()->set_settings(settings);
75 
76     hci::LowEnergyScanner::PacketFilterConfig packet_filter_config(false, 0);
77 
78     // TODO(armansito): Now that the hci::LowEnergyScanner is injected into
79     // |discovery_manager_| rather than constructed by it, a fake implementation
80     // could be injected directly. Consider providing fake behavior here in this
81     // harness rather than using a FakeController.
82     scanner_ =
83         std::make_unique<hci::LegacyLowEnergyScanner>(&fake_address_delegate_,
84                                                       packet_filter_config,
85                                                       transport()->GetWeakPtr(),
86                                                       dispatcher());
87     discovery_manager_ = std::make_unique<LowEnergyDiscoveryManager>(
88         scanner_.get(), &peer_cache_, packet_filter_config, dispatcher());
89     discovery_manager_->AttachInspect(inspector_.GetRoot(), kInspectNodeName);
90 
91     test_device()->set_scan_state_callback([this](auto&& PH1) {
92       OnScanStateChanged(std::forward<decltype(PH1)>(PH1));
93     });
94   }
95 
TearDown()96   void TearDown() override {
97     if (discovery_manager_) {
98       discovery_manager_ = nullptr;
99     }
100     scanner_ = nullptr;
101     test_device()->Stop();
102     TestingBase::TearDown();
103   }
104 
105  protected:
discovery_manager() const106   LowEnergyDiscoveryManager* discovery_manager() const {
107     return discovery_manager_.get();
108   }
109 
110   // Deletes |discovery_manager_|.
DeleteDiscoveryManager()111   void DeleteDiscoveryManager() { discovery_manager_ = nullptr; }
112 
113 #ifndef NINSPECT
InspectHierarchy() const114   inspect::Hierarchy InspectHierarchy() const {
115     return inspect::ReadFromVmo(inspector_.DuplicateVmo()).take_value();
116   }
117 
InspectProperties() const118   std::vector<inspect::PropertyValue> InspectProperties() const {
119     auto hierarchy = InspectHierarchy();
120     auto children = hierarchy.take_children();
121     PW_CHECK(children.size() == 1u);
122     return children.front().node_ptr()->take_properties();
123   }
124 #endif  // NINSPECT
125 
peer_cache()126   PeerCache* peer_cache() { return &peer_cache_; }
127 
128   // Returns the last reported scan state of the FakeController.
scan_enabled() const129   bool scan_enabled() const { return scan_enabled_; }
130 
131   // The scan states that the FakeController has transitioned through.
scan_states() const132   const std::vector<bool> scan_states() const { return scan_states_; }
133 
134   // Sets a callback that will run when the scan state transitions |count|
135   // times.
set_scan_state_handler(size_t count,fit::closure callback)136   void set_scan_state_handler(size_t count, fit::closure callback) {
137     scan_state_callbacks_[count] = std::move(callback);
138   }
139 
140   // Called by FakeController when the scan state changes.
OnScanStateChanged(bool enabled)141   void OnScanStateChanged(bool enabled) {
142     auto scan_type = test_device()->le_scan_state().scan_type;
143     bt_log(DEBUG,
144            "gap-test",
145            "FakeController scan state: %s %s",
146            enabled ? "enabled" : "disabled",
147            scan_type == pw::bluetooth::emboss::LEScanType::ACTIVE ? "active"
148                                                                   : "passive");
149     scan_enabled_ = enabled;
150     scan_states_.push_back(enabled);
151 
152     auto iter = scan_state_callbacks_.find(scan_states_.size());
153     if (iter != scan_state_callbacks_.end()) {
154       iter->second();
155     }
156   }
157 
158   // Registers the following fake peers with the FakeController:
159   //
160   // Peer 0:
161   //   - Connectable, not scannable;
162   //   - General discoverable;
163   //   - UUIDs: 0x180d, 0x180f;
164   //   - Service Data UUIDs: kServiceDataUuid;
165   //   - has name: "Device 0"
166   //
167   // Peer 1:
168   //   - Connectable, not scannable;
169   //   - Limited discoverable;
170   //   - UUIDs: 0x180d;
171   //   - has name: "Device 1"
172   //
173   // Peer 2:
174   //   - Not connectable, not scannable;
175   //   - General discoverable;
176   //   - UUIDs: none;
177   //   - has name: "Device 2"
178   //
179   // Peer 3:
180   //   - Not discoverable;
AddFakePeers()181   void AddFakePeers() {
182     // Peer 0
183     const StaticByteBuffer kAdvData0(
184         // Flags
185         0x02,
186         0x01,
187         0x02,
188 
189         // Complete 16-bit service UUIDs
190         0x05,
191         0x03,
192         0x0d,
193         0x18,
194         0x0f,
195         0x18,
196 
197         // 16-bit service data UUID
198         0x03,
199         DataType::kServiceData16Bit,
200         LowerBits(kServiceDataUuid),
201         UpperBits(kServiceDataUuid),
202 
203         // Complete local name
204         0x09,
205         0x09,
206         'D',
207         'e',
208         'v',
209         'i',
210         'c',
211         'e',
212         ' ',
213         '0');
214     auto fake_peer =
215         std::make_unique<FakePeer>(kAddress0, dispatcher(), true, true);
216     fake_peer->set_advertising_data(kAdvData0);
217     test_device()->AddPeer(std::move(fake_peer));
218 
219     // Peer 1
220     const StaticByteBuffer kAdvData1(
221         // Flags
222         0x02,
223         0x01,
224         0x01,
225 
226         // Complete 16-bit service UUIDs
227         0x03,
228         0x03,
229         0x0d,
230         0x18);
231     fake_peer = std::make_unique<FakePeer>(kAddress1, dispatcher(), true, true);
232     fake_peer->set_advertising_data(kAdvData1);
233     test_device()->AddPeer(std::move(fake_peer));
234 
235     // Peer 2
236     const StaticByteBuffer kAdvData2(
237         // Flags
238         0x02,
239         0x01,
240         0x02,
241 
242         // Complete local name
243         0x09,
244         0x09,
245         'D',
246         'e',
247         'v',
248         'i',
249         'c',
250         'e',
251         ' ',
252         '2');
253     fake_peer =
254         std::make_unique<FakePeer>(kAddress2, dispatcher(), false, false);
255     fake_peer->set_advertising_data(kAdvData2);
256     test_device()->AddPeer(std::move(fake_peer));
257 
258     // Peer 3
259     const StaticByteBuffer kAdvData3(
260         // Flags
261         0x02,
262         0x01,
263         0x00,
264 
265         // Complete local name
266         0x09,
267         0x09,
268         'D',
269         'e',
270         'v',
271         'i',
272         'c',
273         'e',
274         ' ',
275         '3');
276     fake_peer =
277         std::make_unique<FakePeer>(kAddress3, dispatcher(), false, false);
278     fake_peer->set_advertising_data(kAdvData3);
279     test_device()->AddPeer(std::move(fake_peer));
280   }
281 
282   // Creates and returns a discovery session.
StartDiscoverySession(bool active=true,std::vector<hci::DiscoveryFilter> discovery_filters={})283   std::unique_ptr<LowEnergyDiscoverySession> StartDiscoverySession(
284       bool active = true,
285       std::vector<hci::DiscoveryFilter> discovery_filters = {}) {
286     std::unique_ptr<LowEnergyDiscoverySession> session;
287     discovery_manager()->StartDiscovery(
__anone14ffa740302(auto cb_session) 288         active, std::move(discovery_filters), [&](auto cb_session) {
289           PW_CHECK(cb_session);
290           session = std::move(cb_session);
291         });
292 
293     RunUntilIdle();
294     PW_CHECK(session);
295     return session;
296   }
297 
298  private:
299   PeerCache peer_cache_{dispatcher()};
300   hci::FakeLocalAddressDelegate fake_address_delegate_{dispatcher()};
301   std::unique_ptr<hci::LegacyLowEnergyScanner> scanner_;
302   std::unique_ptr<LowEnergyDiscoveryManager> discovery_manager_;
303 
304   bool scan_enabled_;
305   std::vector<bool> scan_states_;
306   std::unordered_map<size_t, fit::closure> scan_state_callbacks_;
307 
308   inspect::Inspector inspector_;
309 
310   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyDiscoveryManagerTest);
311 };
312 
313 using GAP_LowEnergyDiscoveryManagerTest = LowEnergyDiscoveryManagerTest;
314 
TEST_F(LowEnergyDiscoveryManagerTest,StartDiscoveryAndStop)315 TEST_F(LowEnergyDiscoveryManagerTest, StartDiscoveryAndStop) {
316   std::unique_ptr<LowEnergyDiscoverySession> session;
317   discovery_manager()->StartDiscovery(
318       /*active=*/true, {}, [&session](auto cb_session) {
319         session = std::move(cb_session);
320       });
321 
322   RunUntilIdle();
323 
324   // The test fixture will be notified of the change in scan state before we
325   // receive the session.
326   EXPECT_TRUE(scan_enabled());
327   RunUntilIdle();
328 
329   ASSERT_TRUE(session);
330   EXPECT_TRUE(session->alive());
331 
332   session->Stop();
333 
334   RunUntilIdle();
335   EXPECT_FALSE(scan_enabled());
336 }
337 
TEST_F(LowEnergyDiscoveryManagerTest,StartDiscoveryAndStopByDeleting)338 TEST_F(LowEnergyDiscoveryManagerTest, StartDiscoveryAndStopByDeleting) {
339   // Start discovery but don't acquire ownership of the received session. This
340   // should immediately terminate the session.
341   std::unique_ptr<LowEnergyDiscoverySession> session;
342   discovery_manager()->StartDiscovery(
343       /*active=*/true, {}, [&session](auto cb_session) {
344         session = std::move(cb_session);
345       });
346 
347   RunUntilIdle();
348 
349   // The test fixture will be notified of the change in scan state before we
350   // receive the session.
351   EXPECT_TRUE(scan_enabled());
352   RunUntilIdle();
353 
354   ASSERT_TRUE(session);
355   EXPECT_TRUE(session->alive());
356 
357   session = nullptr;
358 
359   RunUntilIdle();
360   EXPECT_FALSE(scan_enabled());
361 }
362 
TEST_F(LowEnergyDiscoveryManagerTest,Destructor)363 TEST_F(LowEnergyDiscoveryManagerTest, Destructor) {
364   // Start discovery with a session, delete the manager and ensure that the
365   // session is inactive with the error callback called.
366   std::unique_ptr<LowEnergyDiscoverySession> session;
367   discovery_manager()->StartDiscovery(
368       /*active=*/true, {}, [&session](auto cb_session) {
369         session = std::move(cb_session);
370       });
371 
372   RunUntilIdle();
373 
374   EXPECT_TRUE(scan_enabled());
375 
376   ASSERT_TRUE(session);
377   EXPECT_TRUE(session->alive());
378 
379   size_t num_errors = 0u;
380   session->set_error_callback([&num_errors]() { num_errors++; });
381 
382   EXPECT_EQ(0u, num_errors);
383   DeleteDiscoveryManager();
384   EXPECT_EQ(1u, num_errors);
385   EXPECT_FALSE(session->alive());
386 }
387 
TEST_F(LowEnergyDiscoveryManagerTest,StartDiscoveryAndStopInCallback)388 TEST_F(LowEnergyDiscoveryManagerTest, StartDiscoveryAndStopInCallback) {
389   // Start discovery but don't acquire ownership of the received session. This
390   // should terminate the session when |session| goes out of scope.
391   discovery_manager()->StartDiscovery(/*active=*/true, {}, [](auto) {});
392 
393   RunUntilIdle();
394   ASSERT_EQ(2u, scan_states().size());
395   EXPECT_TRUE(scan_states()[0]);
396   EXPECT_FALSE(scan_states()[1]);
397 }
398 
TEST_F(LowEnergyDiscoveryManagerTest,StartDiscoveryFailure)399 TEST_F(LowEnergyDiscoveryManagerTest, StartDiscoveryFailure) {
400   test_device()->SetDefaultResponseStatus(
401       hci_spec::kLESetScanEnable,
402       pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
403 
404   // |session| should contain nullptr.
405   discovery_manager()->StartDiscovery(
406       /*active=*/true, {}, [](auto session) { EXPECT_FALSE(session); });
407 
408   RunUntilIdle();
409   EXPECT_FALSE(scan_enabled());
410 }
411 
TEST_F(LowEnergyDiscoveryManagerTest,StartDiscoveryWhileScanning)412 TEST_F(LowEnergyDiscoveryManagerTest, StartDiscoveryWhileScanning) {
413   std::vector<std::unique_ptr<LowEnergyDiscoverySession>> sessions;
414 
415   constexpr size_t kExpectedSessionCount = 5;
416   size_t cb_count = 0u;
417   auto cb = [&cb_count, &sessions](auto session) {
418     sessions.push_back(std::move(session));
419     cb_count++;
420   };
421 
422   discovery_manager()->StartDiscovery(/*active=*/true, {}, cb);
423 
424   RunUntilIdle();
425   EXPECT_TRUE(scan_enabled());
426   EXPECT_EQ(1u, sessions.size());
427 
428   // Add the rest of the sessions. These are expected to succeed immediately but
429   // the callbacks should be called asynchronously.
430   for (size_t i = 1u; i < kExpectedSessionCount; i++) {
431     discovery_manager()->StartDiscovery(/*active=*/true, {}, cb);
432   }
433 
434   RunUntilIdle();
435   EXPECT_TRUE(scan_enabled());
436   EXPECT_EQ(kExpectedSessionCount, sessions.size());
437 
438   // Remove one session from the list. Scan should continue.
439   sessions.pop_back();
440   RunUntilIdle();
441   EXPECT_TRUE(scan_enabled());
442 
443   // Remove all but one session from the list. Scan should continue.
444   sessions.erase(sessions.begin() + 1, sessions.end());
445   RunUntilIdle();
446   EXPECT_TRUE(scan_enabled());
447   EXPECT_EQ(1u, sessions.size());
448 
449   // Remove the last session.
450   sessions.clear();
451   RunUntilIdle();
452   EXPECT_FALSE(scan_enabled());
453 }
454 
TEST_F(LowEnergyDiscoveryManagerTest,StartDiscoveryWhilePendingStart)455 TEST_F(LowEnergyDiscoveryManagerTest, StartDiscoveryWhilePendingStart) {
456   std::vector<std::unique_ptr<LowEnergyDiscoverySession>> sessions;
457 
458   constexpr size_t kExpectedSessionCount = 5;
459   size_t cb_count = 0u;
460   auto cb = [&cb_count, &sessions](auto session) {
461     sessions.push_back(std::move(session));
462     cb_count++;
463   };
464 
465   for (size_t i = 0u; i < kExpectedSessionCount; i++) {
466     discovery_manager()->StartDiscovery(/*active=*/true, {}, cb);
467   }
468 
469   RunUntilIdle();
470   EXPECT_TRUE(scan_enabled());
471   EXPECT_EQ(kExpectedSessionCount, sessions.size());
472 
473   // Remove all sessions. This should stop the scan.
474   sessions.clear();
475   RunUntilIdle();
476   EXPECT_FALSE(scan_enabled());
477 }
478 
TEST_F(LowEnergyDiscoveryManagerTest,StartDiscoveryWhilePendingStartAndStopInCallback)479 TEST_F(LowEnergyDiscoveryManagerTest,
480        StartDiscoveryWhilePendingStartAndStopInCallback) {
481   constexpr size_t kExpectedSessionCount = 5;
482   size_t cb_count = 0u;
483   std::unique_ptr<LowEnergyDiscoverySession> session;
484   auto cb = [&cb_count, &session](auto cb_session) {
485     cb_count++;
486     if (cb_count == kExpectedSessionCount) {
487       // Hold on to only the last session object. The rest should get deleted
488       // within the callback.
489       session = std::move(cb_session);
490     }
491   };
492 
493   for (size_t i = 0u; i < kExpectedSessionCount; i++) {
494     discovery_manager()->StartDiscovery(/*active=*/true, {}, cb);
495   }
496 
497   RunUntilIdle();
498   EXPECT_TRUE(scan_enabled());
499   EXPECT_TRUE(session);
500 
501   RunUntilIdle();
502   EXPECT_EQ(kExpectedSessionCount, cb_count);
503   EXPECT_TRUE(scan_enabled());
504 
505   // Deleting the only remaning session should stop the scan.
506   session = nullptr;
507   RunUntilIdle();
508   EXPECT_FALSE(scan_enabled());
509 }
510 
TEST_F(LowEnergyDiscoveryManagerTest,StartDiscoveryWhilePendingStop)511 TEST_F(LowEnergyDiscoveryManagerTest, StartDiscoveryWhilePendingStop) {
512   std::unique_ptr<LowEnergyDiscoverySession> session;
513 
514   discovery_manager()->StartDiscovery(
515       /*active=*/true, {}, [&session](auto cb_session) {
516         session = std::move(cb_session);
517       });
518 
519   RunUntilIdle();
520   EXPECT_TRUE(scan_enabled());
521   EXPECT_TRUE(session);
522 
523   // Stop the session. This should issue a request to stop the ongoing scan but
524   // the request will remain pending until we run the message loop.
525   session = nullptr;
526 
527   // Request a new session. The discovery manager should restart the scan after
528   // the ongoing one stops.
529   discovery_manager()->StartDiscovery(
530       /*active=*/true, {}, [&session](auto cb_session) {
531         session = std::move(cb_session);
532       });
533 
534   // Discovery should stop and start again.
535   RunUntilIdle();
536   ASSERT_EQ(3u, scan_states().size());
537   EXPECT_TRUE(scan_states()[0]);
538   EXPECT_FALSE(scan_states()[1]);
539   EXPECT_TRUE(scan_states()[2]);
540 }
541 
TEST_F(LowEnergyDiscoveryManagerTest,StartDiscoveryFailureManyPending)542 TEST_F(LowEnergyDiscoveryManagerTest, StartDiscoveryFailureManyPending) {
543   test_device()->SetDefaultResponseStatus(
544       hci_spec::kLESetScanEnable,
545       pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
546 
547   constexpr size_t kExpectedSessionCount = 5;
548   size_t cb_count = 0u;
549   auto cb = [&cb_count](auto session) {
550     // |session| should contain nullptr as the request will fail.
551     EXPECT_FALSE(session);
552     cb_count++;
553   };
554 
555   for (size_t i = 0u; i < kExpectedSessionCount; i++) {
556     discovery_manager()->StartDiscovery(/*active=*/true, {}, cb);
557   }
558 
559   RunUntilIdle();
560   EXPECT_FALSE(scan_enabled());
561 }
562 
TEST_F(LowEnergyDiscoveryManagerTest,ScanPeriodRestart)563 TEST_F(LowEnergyDiscoveryManagerTest, ScanPeriodRestart) {
564   constexpr size_t kNumScanStates = 3;
565 
566   discovery_manager()->set_scan_period(kTestScanPeriod);
567 
568   std::unique_ptr<LowEnergyDiscoverySession> session;
569   discovery_manager()->StartDiscovery(
570       /*active=*/true, {}, [&session](auto cb_session) {
571         session = std::move(cb_session);
572       });
573 
574   // We should observe the scan state become enabled -> disabled -> enabled.
575   RunUntilIdle();
576   EXPECT_TRUE(scan_enabled());
577 
578   // End the scan period.
579   RunFor(kTestScanPeriod);
580   ASSERT_EQ(kNumScanStates, scan_states().size());
581   EXPECT_TRUE(scan_states()[0]);
582   EXPECT_FALSE(scan_states()[1]);
583   EXPECT_TRUE(scan_states()[2]);
584 }
585 
TEST_F(LowEnergyDiscoveryManagerTest,ScanPeriodRestartFailure)586 TEST_F(LowEnergyDiscoveryManagerTest, ScanPeriodRestartFailure) {
587   constexpr size_t kNumScanStates = 2;
588 
589   discovery_manager()->set_scan_period(kTestScanPeriod);
590 
591   std::unique_ptr<LowEnergyDiscoverySession> session;
592   bool session_error = false;
593   discovery_manager()->StartDiscovery(
594       /*active=*/true, {}, [&](auto cb_session) {
595         session = std::move(cb_session);
596         session->set_error_callback([&session_error] { session_error = true; });
597       });
598 
599   // The controller will fail to restart scanning after scanning stops at the
600   // end of the period. The scan state will transition twice (-> enabled ->
601   // disabled).
602   set_scan_state_handler(kNumScanStates, [this] {
603     test_device()->SetDefaultResponseStatus(
604         hci_spec::kLESetScanEnable,
605         pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
606   });
607 
608   RunUntilIdle();
609   EXPECT_TRUE(scan_enabled());
610 
611   // End the scan period. The scan should not restart.
612   RunFor(kTestScanPeriod);
613 
614   ASSERT_EQ(kNumScanStates, scan_states().size());
615   EXPECT_TRUE(scan_states()[0]);
616   EXPECT_FALSE(scan_states()[1]);
617   EXPECT_TRUE(session_error);
618 }
619 
TEST_F(LowEnergyDiscoveryManagerTest,ScanPeriodRestartRemoveSession)620 TEST_F(LowEnergyDiscoveryManagerTest, ScanPeriodRestartRemoveSession) {
621   constexpr size_t kNumScanStates = 4;
622 
623   discovery_manager()->set_scan_period(kTestScanPeriod);
624 
625   std::unique_ptr<LowEnergyDiscoverySession> session;
626   discovery_manager()->StartDiscovery(
627       /*active=*/true, {}, [&session](auto cb_session) {
628         session = std::move(cb_session);
629       });
630 
631   // We should observe 3 scan state transitions (-> enabled -> disabled ->
632   // enabled).
633   set_scan_state_handler(kNumScanStates - 1, [this, &session] {
634     ASSERT_TRUE(session);
635     EXPECT_TRUE(scan_enabled());
636 
637     // At this point the fake controller has updated its state but the discovery
638     // manager has not processed the restarted scan. We should be able to remove
639     // the current session and the state should ultimately become disabled.
640     session.reset();
641   });
642 
643   RunUntilIdle();
644   EXPECT_TRUE(scan_enabled());
645 
646   // End the scan period.
647   RunFor(kTestScanPeriod);
648   EXPECT_THAT(scan_states(), ::testing::ElementsAre(true, false, true, false));
649 }
650 
TEST_F(LowEnergyDiscoveryManagerTest,ScanPeriodRemoveSessionDuringRestart)651 TEST_F(LowEnergyDiscoveryManagerTest, ScanPeriodRemoveSessionDuringRestart) {
652   constexpr size_t kNumScanStates = 2;
653 
654   // Set a very short scan period for the sake of the test.
655   discovery_manager()->set_scan_period(kTestScanPeriod);
656 
657   std::unique_ptr<LowEnergyDiscoverySession> session;
658   discovery_manager()->StartDiscovery(
659       /*active=*/true, {}, [&session](auto cb_session) {
660         session = std::move(cb_session);
661       });
662 
663   // The controller will fail to restart scanning after scanning stops at the
664   // end of the period. The scan state will transition twice (-> enabled ->
665   // disabled).
666   set_scan_state_handler(kNumScanStates, [this, &session] {
667     ASSERT_TRUE(session);
668     EXPECT_FALSE(scan_enabled());
669 
670     // Stop the session before the discovery manager processes the event. It
671     // should detect this and discontinue the scan.
672     session.reset();
673   });
674 
675   RunUntilIdle();
676   EXPECT_TRUE(scan_enabled());
677 
678   // End the scan period.
679   RunFor(kTestScanPeriod);
680   EXPECT_THAT(scan_states(), ::testing::ElementsAre(true, false));
681 }
682 
TEST_F(LowEnergyDiscoveryManagerTest,ScanPeriodRestartRemoveAndAddSession)683 TEST_F(LowEnergyDiscoveryManagerTest, ScanPeriodRestartRemoveAndAddSession) {
684   constexpr size_t kNumScanPeriodRestartStates = 3;
685   constexpr size_t kTotalNumStates = 5;
686 
687   // Set a very short scan period for the sake of the test.
688   discovery_manager()->set_scan_period(kTestScanPeriod);
689 
690   std::unique_ptr<LowEnergyDiscoverySession> session;
691   auto cb = [&session](auto cb_session) { session = std::move(cb_session); };
692   discovery_manager()->StartDiscovery(/*active=*/true, {}, cb);
693 
694   // We should observe 3 scan state transitions (-> enabled -> disabled ->
695   // enabled).
696   set_scan_state_handler(kNumScanPeriodRestartStates, [this, &session, cb] {
697     ASSERT_TRUE(session);
698     EXPECT_TRUE(scan_enabled());
699 
700     // At this point the fake controller has updated its state but the discovery
701     // manager has not processed the restarted scan. We should be able to remove
702     // the current session and create a new one and the state should update
703     // accordingly.
704     session.reset();
705     discovery_manager()->StartDiscovery(/*active=*/true, {}, cb);
706   });
707 
708   RunUntilIdle();
709   EXPECT_TRUE(scan_enabled());
710 
711   // End the scan period.
712   RunFor(kTestScanPeriod);
713 
714   // Scan should have been disabled and re-enabled.
715   ASSERT_EQ(kTotalNumStates, scan_states().size());
716   EXPECT_TRUE(scan_states()[0]);
717   EXPECT_FALSE(scan_states()[1]);
718   EXPECT_TRUE(scan_states()[2]);
719 }
720 
TEST_F(LowEnergyDiscoveryManagerTest,StartDiscoveryWithFilters)721 TEST_F(LowEnergyDiscoveryManagerTest, StartDiscoveryWithFilters) {
722   AddFakePeers();
723 
724   std::vector<std::unique_ptr<LowEnergyDiscoverySession>> sessions;
725 
726   // Set a short scan period so that we that we process events for multiple scan
727   // periods during the test.
728   discovery_manager()->set_scan_period(std::chrono::milliseconds(200));
729 
730   // Session 0 is interested in performing general discovery.
731   std::unordered_set<DeviceAddress> peers_session0;
732   LowEnergyDiscoverySession::PeerFoundFunction result_cb =
733       [&peers_session0](const auto& peer) {
734         peers_session0.insert(peer.address());
735       };
736 
737   hci::DiscoveryFilter discovery_filter;
738   discovery_filter.SetGeneralDiscoveryFlags();
739   std::vector<hci::DiscoveryFilter> discovery_filters;
740   discovery_filters.push_back(discovery_filter);
741   sessions.push_back(StartDiscoverySession(/*active=*/true, discovery_filters));
742   sessions[0]->SetResultCallback(std::move(result_cb));
743 
744   // Session 1 is interested in performing limited discovery.
745   hci::DiscoveryFilter discovery_filter1;
746   discovery_filter1.set_flags(AdvFlag::kLELimitedDiscoverableMode);
747   std::vector<hci::DiscoveryFilter> discovery_filters1;
748   discovery_filters1.push_back(discovery_filter1);
749 
750   std::unordered_set<DeviceAddress> peers_session1;
751   result_cb = [&peers_session1](const auto& peer) {
752     peers_session1.insert(peer.address());
753   };
754   sessions.push_back(
755       StartDiscoverySession(/*active=*/true, discovery_filters1));
756   sessions[1]->SetResultCallback(std::move(result_cb));
757 
758   // Session 2 is interested in peers with UUID 0x180d.
759   hci::DiscoveryFilter discovery_filter2;
760   uint16_t uuid = 0x180d;
761   discovery_filter2.set_service_uuids({UUID(uuid)});
762   std::vector<hci::DiscoveryFilter> discovery_filters2;
763   discovery_filters2.push_back(discovery_filter2);
764 
765   std::unordered_set<DeviceAddress> peers_session2;
766   result_cb = [&peers_session2](const auto& peer) {
767     peers_session2.insert(peer.address());
768   };
769   sessions.push_back(
770       StartDiscoverySession(/*active=*/true, discovery_filters2));
771   sessions[2]->SetResultCallback(std::move(result_cb));
772 
773   // Session 3 is interested in peers whose names contain "Device".
774   hci::DiscoveryFilter discovery_filter3;
775   discovery_filter3.set_name_substring("Device");
776   std::vector<hci::DiscoveryFilter> discovery_filters3;
777   discovery_filters3.push_back(discovery_filter3);
778 
779   std::unordered_set<DeviceAddress> peers_session3;
780   result_cb = [&peers_session3](const auto& peer) {
781     peers_session3.insert(peer.address());
782   };
783   sessions.push_back(
784       StartDiscoverySession(/*active=*/true, discovery_filters3));
785   sessions[3]->SetResultCallback(std::move(result_cb));
786 
787   // Session 4 is interested in non-connectable peers.
788   hci::DiscoveryFilter discovery_filter4;
789   discovery_filter4.set_connectable(false);
790   std::vector<hci::DiscoveryFilter> discovery_filters4;
791   discovery_filters4.push_back(discovery_filter4);
792 
793   std::unordered_set<DeviceAddress> peers_session4;
794   result_cb = [&peers_session4](const auto& peer) {
795     peers_session4.insert(peer.address());
796   };
797   sessions.push_back(
798       StartDiscoverySession(/*active=*/true, discovery_filters4));
799   sessions[4]->SetResultCallback(std::move(result_cb));
800 
801   // Session 5 is interested in peers with UUID 0x180d and service data UUID
802   // 0x1234.
803   hci::DiscoveryFilter discovery_filter5;
804   discovery_filter5.set_service_uuids({UUID(uuid)});
805   discovery_filter5.set_service_data_uuids({UUID(kServiceDataUuid)});
806   std::vector<hci::DiscoveryFilter> discovery_filters5;
807   discovery_filters5.push_back(discovery_filter5);
808 
809   std::unordered_set<DeviceAddress> peers_session5;
810   result_cb = [&peers_session5](const auto& peer) {
811     peers_session5.insert(peer.address());
812   };
813   sessions.push_back(
814       StartDiscoverySession(/*active=*/true, discovery_filters5));
815 
816   sessions[5]->SetResultCallback(std::move(result_cb));
817 
818   RunUntilIdle();
819 
820   EXPECT_EQ(6u, sessions.size());
821 
822   // At this point all sessions should have processed all peers at least once.
823 
824   // Session 0: Should have seen all peers except for peer 3, which is
825   // non-discoverable.
826   EXPECT_EQ(3u, peers_session0.size());
827   EXPECT_THAT(peers_session0, ::testing::Contains(kAddress0));
828   EXPECT_THAT(peers_session0, ::testing::Contains(kAddress1));
829   EXPECT_THAT(peers_session0, ::testing::Contains(kAddress2));
830 
831   // Session 1: Should have only seen peer 1.
832   EXPECT_EQ(1u, peers_session1.size());
833   EXPECT_THAT(peers_session1, ::testing::Contains(kAddress1));
834 
835   // Session 2: Should have only seen peers 0 and 1
836   EXPECT_EQ(2u, peers_session2.size());
837   EXPECT_THAT(peers_session2, ::testing::Contains(kAddress0));
838   EXPECT_THAT(peers_session2, ::testing::Contains(kAddress1));
839 
840   // Session 3: Should have only seen peers 0, 2, and 3
841   EXPECT_EQ(3u, peers_session3.size());
842   EXPECT_THAT(peers_session3, ::testing::Contains(kAddress0));
843   EXPECT_THAT(peers_session3, ::testing::Contains(kAddress2));
844   EXPECT_THAT(peers_session3, ::testing::Contains(kAddress3));
845 
846   // Session 4: Should have seen peers 2 and 3
847   EXPECT_EQ(2u, peers_session4.size());
848   EXPECT_THAT(peers_session4, ::testing::Contains(kAddress2));
849   EXPECT_THAT(peers_session4, ::testing::Contains(kAddress3));
850 
851   // Session 5: Should only see peer 0.
852   EXPECT_EQ(1u, peers_session5.size());
853   EXPECT_THAT(peers_session5, ::testing::Contains(kAddress0));
854 }
855 
TEST_F(LowEnergyDiscoveryManagerTest,StartDiscoveryWithFiltersCachedPeerNotifications)856 TEST_F(LowEnergyDiscoveryManagerTest,
857        StartDiscoveryWithFiltersCachedPeerNotifications) {
858   AddFakePeers();
859 
860   std::vector<std::unique_ptr<LowEnergyDiscoverySession>> sessions;
861 
862   // Set a long scan period to make sure that the FakeController sends
863   // advertising reports only once.
864   discovery_manager()->set_scan_period(std::chrono::seconds(20));
865 
866   // Session 0 is interested in performing general discovery.
867   hci::DiscoveryFilter discovery_filter;
868   discovery_filter.SetGeneralDiscoveryFlags();
869   std::vector<hci::DiscoveryFilter> discovery_filters;
870   discovery_filters.push_back(discovery_filter);
871 
872   std::unordered_set<DeviceAddress> peers_session0;
873   LowEnergyDiscoverySession::PeerFoundFunction result_cb =
874       [&peers_session0](const auto& peer) {
875         peers_session0.insert(peer.address());
876       };
877   sessions.push_back(StartDiscoverySession(/*active=*/true, discovery_filters));
878   sessions[0]->SetResultCallback(std::move(result_cb));
879 
880   RunUntilIdle();
881   ASSERT_EQ(3u, peers_session0.size());
882 
883   // Session 1 is interested in performing limited discovery.
884   hci::DiscoveryFilter discovery_filter1;
885   discovery_filter1.set_flags(AdvFlag::kLELimitedDiscoverableMode);
886   std::vector<hci::DiscoveryFilter> discovery_filters1;
887   discovery_filters1.push_back(discovery_filter1);
888 
889   std::unordered_set<DeviceAddress> peers_session1;
890   result_cb = [&peers_session1](const auto& peer) {
891     peers_session1.insert(peer.address());
892   };
893   sessions.push_back(
894       StartDiscoverySession(/*active=*/true, discovery_filters1));
895   sessions[1]->SetResultCallback(std::move(result_cb));
896 
897   // Session 2 is interested in peers with UUID 0x180d.
898   hci::DiscoveryFilter discovery_filter2;
899   uint16_t uuid = 0x180d;
900   discovery_filter2.set_service_uuids({UUID(uuid)});
901   std::vector<hci::DiscoveryFilter> discovery_filters2;
902   discovery_filters2.push_back(discovery_filter2);
903 
904   std::unordered_set<DeviceAddress> peers_session2;
905   result_cb = [&peers_session2](const auto& peer) {
906     peers_session2.insert(peer.address());
907   };
908   sessions.push_back(
909       StartDiscoverySession(/*active=*/true, discovery_filters2));
910 
911   sessions[2]->SetResultCallback(std::move(result_cb));
912 
913   // Session 3 is interested in peers whose names contain "Device".
914   hci::DiscoveryFilter discovery_filter3;
915   discovery_filter3.set_name_substring("Device");
916   std::vector<hci::DiscoveryFilter> discovery_filters3;
917   discovery_filters3.push_back(discovery_filter3);
918 
919   std::unordered_set<DeviceAddress> peers_session3;
920   result_cb = [&peers_session3](const auto& peer) {
921     peers_session3.insert(peer.address());
922   };
923   sessions.push_back(
924       StartDiscoverySession(/*active=*/true, discovery_filters3));
925   sessions[3]->SetResultCallback(std::move(result_cb));
926 
927   // Session 4 is interested in non-connectable peers.
928   hci::DiscoveryFilter discovery_filter4;
929   discovery_filter4.set_connectable(false);
930   std::vector<hci::DiscoveryFilter> discovery_filters4;
931   discovery_filters4.push_back(discovery_filter4);
932 
933   std::unordered_set<DeviceAddress> peers_session4;
934   result_cb = [&peers_session4](const auto& peer) {
935     peers_session4.insert(peer.address());
936   };
937   sessions.push_back(
938       StartDiscoverySession(/*active=*/true, discovery_filters4));
939   sessions[4]->SetResultCallback(std::move(result_cb));
940 
941   EXPECT_EQ(5u, sessions.size());
942   RunUntilIdle();
943 
944 #define EXPECT_CONTAINS(addr, dev_list) \
945   EXPECT_TRUE(dev_list.find(addr) != dev_list.end())
946   // At this point all sessions should have processed all peers at least once
947   // without running the message loop; results for Sessions 1, 2, 3, and 4
948   // should have come from the cache.
949 
950   // Session 0: Should have seen all peers except for peer 3, which is
951   // non-discoverable.
952   EXPECT_EQ(3u, peers_session0.size());
953   EXPECT_CONTAINS(kAddress0, peers_session0);
954   EXPECT_CONTAINS(kAddress1, peers_session0);
955   EXPECT_CONTAINS(kAddress2, peers_session0);
956 
957   // Session 1: Should have only seen peer 1.
958   EXPECT_EQ(1u, peers_session1.size());
959   EXPECT_CONTAINS(kAddress1, peers_session1);
960 
961   // Session 2: Should have only seen peers 0 and 1
962   EXPECT_EQ(2u, peers_session2.size());
963   EXPECT_CONTAINS(kAddress0, peers_session2);
964   EXPECT_CONTAINS(kAddress1, peers_session2);
965 
966   // Session 3: Should have only seen peers 0, 2, and 3
967   EXPECT_EQ(3u, peers_session3.size());
968   EXPECT_CONTAINS(kAddress0, peers_session3);
969   EXPECT_CONTAINS(kAddress2, peers_session3);
970   EXPECT_CONTAINS(kAddress3, peers_session3);
971 
972   // Session 4: Should have seen peers 2 and 3
973   EXPECT_EQ(2u, peers_session4.size());
974   EXPECT_CONTAINS(kAddress2, peers_session4);
975   EXPECT_CONTAINS(kAddress3, peers_session4);
976 
977 #undef EXPECT_CONTAINS
978 }
979 
TEST_F(LowEnergyDiscoveryManagerTest,DirectedAdvertisingEventFromUnknownPeer)980 TEST_F(LowEnergyDiscoveryManagerTest, DirectedAdvertisingEventFromUnknownPeer) {
981   auto fake_peer = std::make_unique<FakePeer>(kAddress0,
982                                               dispatcher(),
983                                               /*connectable=*/true,
984                                               /*scannable=*/false);
985   fake_peer->set_directed_advertising_enabled(true);
986   test_device()->AddPeer(std::move(fake_peer));
987 
988   int connectable_count = 0;
989   discovery_manager()->set_peer_connectable_callback(
990       [&](auto) { connectable_count++; });
991   discovery_manager()->set_scan_period(kTestScanPeriod);
992 
993   auto active_session = StartDiscoverySession();
994   int active_count = 0;
995   active_session->SetResultCallback([&](auto&) { active_count++; });
996 
997   auto passive_session = StartDiscoverySession(/*active=*/false);
998   int passive_count = 0;
999   passive_session->SetResultCallback([&](auto&) { passive_count++; });
1000 
1001   RunUntilIdle();
1002   ASSERT_TRUE(active_session);
1003   ASSERT_TRUE(passive_session);
1004   EXPECT_EQ(0, connectable_count);
1005   EXPECT_EQ(0, active_count);
1006   EXPECT_EQ(0, passive_count);
1007 }
1008 
TEST_F(LowEnergyDiscoveryManagerTest,DirectedAdvertisingEventFromKnownNonConnectablePeer)1009 TEST_F(LowEnergyDiscoveryManagerTest,
1010        DirectedAdvertisingEventFromKnownNonConnectablePeer) {
1011   auto fake_peer = std::make_unique<FakePeer>(kAddress0,
1012                                               dispatcher(),
1013                                               /*connectable=*/false,
1014                                               /*scannable=*/false);
1015   fake_peer->set_directed_advertising_enabled(true);
1016   test_device()->AddPeer(std::move(fake_peer));
1017   Peer* peer = peer_cache()->NewPeer(kAddress0, /*connectable=*/false);
1018   ASSERT_TRUE(peer);
1019 
1020   int connectable_count = 0;
1021   discovery_manager()->set_peer_connectable_callback(
1022       [&](auto) { connectable_count++; });
1023   discovery_manager()->set_scan_period(kTestScanPeriod);
1024 
1025   auto active_session = StartDiscoverySession();
1026   int active_count = 0;
1027   active_session->SetResultCallback([&](auto&) { active_count++; });
1028 
1029   auto passive_session = StartDiscoverySession(/*active=*/false);
1030   int passive_count = 0;
1031   passive_session->SetResultCallback([&](auto&) { passive_count++; });
1032 
1033   RunFor(kTestScanPeriod);
1034   ASSERT_TRUE(active_session);
1035   ASSERT_TRUE(passive_session);
1036   EXPECT_EQ(0, connectable_count);
1037   EXPECT_EQ(0, active_count);
1038   EXPECT_EQ(1, passive_count);
1039 }
1040 
TEST_F(LowEnergyDiscoveryManagerTest,DirectedAdvertisingEventFromKnownConnectablePeer)1041 TEST_F(LowEnergyDiscoveryManagerTest,
1042        DirectedAdvertisingEventFromKnownConnectablePeer) {
1043   auto fake_peer = std::make_unique<FakePeer>(kAddress0,
1044                                               dispatcher(),
1045                                               /*connectable=*/true,
1046                                               /*scannable=*/false);
1047   fake_peer->set_directed_advertising_enabled(true);
1048   test_device()->AddPeer(std::move(fake_peer));
1049   Peer* peer = peer_cache()->NewPeer(kAddress0, /*connectable=*/true);
1050   ASSERT_TRUE(peer);
1051 
1052   int connectable_count = 0;
1053   discovery_manager()->set_peer_connectable_callback([&](Peer* callback_peer) {
1054     ASSERT_TRUE(callback_peer);
1055     EXPECT_TRUE(callback_peer->le());
1056     EXPECT_EQ(peer, callback_peer);
1057     connectable_count++;
1058   });
1059   discovery_manager()->set_scan_period(kTestScanPeriod);
1060 
1061   auto active_session = StartDiscoverySession();
1062   int active_count = 0;
1063   active_session->SetResultCallback([&](auto&) { active_count++; });
1064 
1065   auto passive_session = StartDiscoverySession(/*active=*/false);
1066   int passive_count = 0;
1067   passive_session->SetResultCallback([&](auto&) { passive_count++; });
1068 
1069   RunFor(kTestScanPeriod);
1070   ASSERT_TRUE(active_session);
1071   ASSERT_TRUE(passive_session);
1072   // Connectable callback will be notified at the start of each scan period.
1073   EXPECT_EQ(2, connectable_count);
1074   EXPECT_EQ(0, active_count);
1075   EXPECT_EQ(1, passive_count);
1076 }
1077 
TEST_F(LowEnergyDiscoveryManagerTest,ScanResultUpgradesKnownBrEdrPeerToDualMode)1078 TEST_F(LowEnergyDiscoveryManagerTest,
1079        ScanResultUpgradesKnownBrEdrPeerToDualMode) {
1080   Peer* peer = peer_cache()->NewPeer(kAddrAlias0, /*connectable=*/true);
1081   ASSERT_TRUE(peer);
1082   ASSERT_EQ(peer, peer_cache()->FindByAddress(kAddress0));
1083   ASSERT_EQ(TechnologyType::kClassic, peer->technology());
1084 
1085   AddFakePeers();
1086 
1087   discovery_manager()->set_scan_period(kTestScanPeriod);
1088 
1089   std::unordered_set<DeviceAddress> addresses_found;
1090   LowEnergyDiscoverySession::PeerFoundFunction result_cb =
1091       [&addresses_found](const auto& peer) {
1092         addresses_found.insert(peer.address());
1093       };
1094 
1095   hci::DiscoveryFilter discovery_filter;
1096   discovery_filter.SetGeneralDiscoveryFlags();
1097   std::vector<hci::DiscoveryFilter> discovery_filters;
1098   discovery_filters.push_back(discovery_filter);
1099 
1100   auto session = StartDiscoverySession(/*active=*/true, discovery_filters);
1101   session->SetResultCallback(std::move(result_cb));
1102 
1103   RunUntilIdle();
1104 
1105   ASSERT_EQ(3u, addresses_found.size());
1106   EXPECT_TRUE(addresses_found.find(kAddrAlias0) != addresses_found.end());
1107   EXPECT_EQ(TechnologyType::kDualMode, peer->technology());
1108 }
1109 
TEST_F(LowEnergyDiscoveryManagerTest,StartAndDisablePassiveScan)1110 TEST_F(LowEnergyDiscoveryManagerTest, StartAndDisablePassiveScan) {
1111   ASSERT_FALSE(test_device()->le_scan_state().enabled);
1112 
1113   auto session = StartDiscoverySession(/*active=*/false);
1114   RunUntilIdle();
1115   EXPECT_TRUE(test_device()->le_scan_state().enabled);
1116   EXPECT_EQ(pw::bluetooth::emboss::LEScanType::PASSIVE,
1117             test_device()->le_scan_state().scan_type);
1118   EXPECT_FALSE(discovery_manager()->discovering());
1119 
1120   session.reset();
1121   RunUntilIdle();
1122   EXPECT_FALSE(test_device()->le_scan_state().enabled);
1123 }
1124 
TEST_F(LowEnergyDiscoveryManagerTest,StartAndDisablePassiveScanQuickly)1125 TEST_F(LowEnergyDiscoveryManagerTest, StartAndDisablePassiveScanQuickly) {
1126   ASSERT_FALSE(test_device()->le_scan_state().enabled);
1127 
1128   // Session will be destroyed in callback, stopping scan.
1129   discovery_manager()->StartDiscovery(
1130       /*active=*/false, {}, [&](auto cb_session) { PW_CHECK(cb_session); });
1131   RunUntilIdle();
1132 
1133   EXPECT_FALSE(test_device()->le_scan_state().enabled);
1134   EXPECT_EQ(2u, scan_states().size());
1135 
1136   // This should not result in a request to stop scan because both pending
1137   // requests will be processed at the same time, and second call to
1138   // StartDiscovery() retains its session.
1139   discovery_manager()->StartDiscovery(
1140       /*active=*/false, {}, [&](auto cb_session) { PW_CHECK(cb_session); });
1141   std::unique_ptr<LowEnergyDiscoverySession> session;
1142   discovery_manager()->StartDiscovery(
1143       /*active=*/false, {}, [&](auto cb_session) {
1144         PW_CHECK(cb_session);
1145         session = std::move(cb_session);
1146       });
1147   RunUntilIdle();
1148   EXPECT_EQ(3u, scan_states().size());
1149 
1150   EXPECT_TRUE(test_device()->le_scan_state().enabled);
1151 }
1152 
TEST_F(LowEnergyDiscoveryManagerTest,EnablePassiveScanDuringActiveScanAndDisableActiveScanCausesDowngrade)1153 TEST_F(LowEnergyDiscoveryManagerTest,
1154        EnablePassiveScanDuringActiveScanAndDisableActiveScanCausesDowngrade) {
1155   auto active_session = StartDiscoverySession();
1156   ASSERT_TRUE(active_session);
1157   ASSERT_TRUE(test_device()->le_scan_state().enabled);
1158   ASSERT_EQ(pw::bluetooth::emboss::LEScanType::ACTIVE,
1159             test_device()->le_scan_state().scan_type);
1160 
1161   // The scan state should transition to enabled.
1162   ASSERT_EQ(1u, scan_states().size());
1163   EXPECT_TRUE(scan_states()[0]);
1164 
1165   // Enabling passive scans should not disable the active scan.
1166   auto passive_session = StartDiscoverySession(false);
1167   RunUntilIdle();
1168   ASSERT_EQ(pw::bluetooth::emboss::LEScanType::ACTIVE,
1169             test_device()->le_scan_state().scan_type);
1170   EXPECT_TRUE(test_device()->le_scan_state().enabled);
1171   EXPECT_EQ(1u, scan_states().size());
1172 
1173   // Stopping the active session should fall back to passive scan.
1174   active_session = nullptr;
1175   RunUntilIdle();
1176   EXPECT_TRUE(test_device()->le_scan_state().enabled);
1177   EXPECT_EQ(pw::bluetooth::emboss::LEScanType::PASSIVE,
1178             test_device()->le_scan_state().scan_type);
1179   EXPECT_THAT(scan_states(), ::testing::ElementsAre(true, false, true));
1180 }
1181 
TEST_F(LowEnergyDiscoveryManagerTest,DisablePassiveScanDuringActiveScan)1182 TEST_F(LowEnergyDiscoveryManagerTest, DisablePassiveScanDuringActiveScan) {
1183   auto active_session = StartDiscoverySession();
1184   ASSERT_TRUE(active_session);
1185   ASSERT_TRUE(test_device()->le_scan_state().enabled);
1186   ASSERT_EQ(pw::bluetooth::emboss::LEScanType::ACTIVE,
1187             test_device()->le_scan_state().scan_type);
1188 
1189   // The scan state should transition to enabled.
1190   ASSERT_EQ(1u, scan_states().size());
1191   EXPECT_TRUE(scan_states()[0]);
1192 
1193   // Enabling passive scans should not disable the active scan.
1194   auto passive_session = StartDiscoverySession(false);
1195   RunUntilIdle();
1196   ASSERT_EQ(pw::bluetooth::emboss::LEScanType::ACTIVE,
1197             test_device()->le_scan_state().scan_type);
1198   EXPECT_TRUE(test_device()->le_scan_state().enabled);
1199   EXPECT_EQ(1u, scan_states().size());
1200 
1201   // Disabling the passive scan should not disable the active scan.
1202   passive_session.reset();
1203   RunUntilIdle();
1204   ASSERT_EQ(pw::bluetooth::emboss::LEScanType::ACTIVE,
1205             test_device()->le_scan_state().scan_type);
1206   EXPECT_TRUE(test_device()->le_scan_state().enabled);
1207   EXPECT_EQ(1u, scan_states().size());
1208 
1209   // Stopping the active session should stop scans.
1210   active_session = nullptr;
1211   RunUntilIdle();
1212   EXPECT_FALSE(test_device()->le_scan_state().enabled);
1213   EXPECT_THAT(scan_states(), ::testing::ElementsAre(true, false));
1214 }
1215 
TEST_F(LowEnergyDiscoveryManagerTest,StartActiveScanDuringPassiveScan)1216 TEST_F(LowEnergyDiscoveryManagerTest, StartActiveScanDuringPassiveScan) {
1217   auto passive_session = StartDiscoverySession(false);
1218   RunUntilIdle();
1219   ASSERT_TRUE(test_device()->le_scan_state().enabled);
1220   ASSERT_EQ(pw::bluetooth::emboss::LEScanType::PASSIVE,
1221             test_device()->le_scan_state().scan_type);
1222 
1223   // The scan state should transition to enabled.
1224   ASSERT_EQ(1u, scan_states().size());
1225   EXPECT_TRUE(scan_states()[0]);
1226 
1227   // Starting discovery should turn off the passive scan and initiate an active
1228   // scan.
1229   auto active_session = StartDiscoverySession();
1230   EXPECT_TRUE(active_session);
1231   EXPECT_TRUE(test_device()->le_scan_state().enabled);
1232   EXPECT_EQ(pw::bluetooth::emboss::LEScanType::ACTIVE,
1233             test_device()->le_scan_state().scan_type);
1234   EXPECT_THAT(scan_states(), ::testing::ElementsAre(true, false, true));
1235 }
1236 
TEST_F(LowEnergyDiscoveryManagerTest,StartActiveScanWhileStartingPassiveScan)1237 TEST_F(LowEnergyDiscoveryManagerTest, StartActiveScanWhileStartingPassiveScan) {
1238   std::unique_ptr<LowEnergyDiscoverySession> passive_session;
1239   discovery_manager()->StartDiscovery(
1240       /*active=*/false, {}, [&](auto cb_session) {
1241         PW_CHECK(cb_session);
1242         passive_session = std::move(cb_session);
1243       });
1244   ASSERT_FALSE(passive_session);
1245 
1246   std::unique_ptr<LowEnergyDiscoverySession> active_session;
1247   discovery_manager()->StartDiscovery(
1248       /*active=*/true, {}, [&](auto cb_session) {
1249         PW_CHECK(cb_session);
1250         active_session = std::move(cb_session);
1251       });
1252   ASSERT_FALSE(active_session);
1253 
1254   // Scan should not be enabled yet.
1255   EXPECT_FALSE(test_device()->le_scan_state().enabled);
1256   EXPECT_TRUE(scan_states().empty());
1257 
1258   // Process all the requests. We should observe multiple state transitions:
1259   // -> enabled (passive) -> disabled -> enabled (active)
1260   RunUntilIdle();
1261   ASSERT_TRUE(test_device()->le_scan_state().enabled);
1262   EXPECT_EQ(pw::bluetooth::emboss::LEScanType::ACTIVE,
1263             test_device()->le_scan_state().scan_type);
1264   EXPECT_THAT(scan_states(), ::testing::ElementsAre(true, false, true));
1265 }
1266 
1267 // Emulate a number of connectable and non-connectable advertisers in both
1268 // undirected connectable and directed connectable modes. This test is to ensure
1269 // that the only peers notified during a passive scan are from connectable peers
1270 // that are already in the cache.
TEST_F(LowEnergyDiscoveryManagerTest,PeerConnectableCallbackOnlyHandlesEventsFromKnownConnectableDevices)1271 TEST_F(LowEnergyDiscoveryManagerTest,
1272        PeerConnectableCallbackOnlyHandlesEventsFromKnownConnectableDevices) {
1273   // Address 0: undirected connectable; added to cache below
1274   {
1275     auto peer = std::make_unique<FakePeer>(kAddress0,
1276                                            dispatcher(),
1277                                            /*connectable=*/true,
1278                                            /*scannable=*/true);
1279     test_device()->AddPeer(std::move(peer));
1280   }
1281   // Address 1: undirected connectable; NOT in cache
1282   {
1283     auto peer = std::make_unique<FakePeer>(kAddress1,
1284                                            dispatcher(),
1285                                            /*connectable=*/true,
1286                                            /*scannable=*/true);
1287     test_device()->AddPeer(std::move(peer));
1288   }
1289   // Address 2: not connectable; added to cache below
1290   {
1291     auto peer = std::make_unique<FakePeer>(kAddress2,
1292                                            dispatcher(),
1293                                            /*connectable=*/false,
1294                                            /*scannable=*/false);
1295     test_device()->AddPeer(std::move(peer));
1296   }
1297   // Address 3: not connectable but directed advertising (NOTE: although a
1298   // directed advertising PDU is inherently connectable, it is theoretically
1299   // possible for the peer_cache() to be in this state, even if unlikely in
1300   // practice).
1301   //
1302   // added to cache below
1303   {
1304     auto peer = std::make_unique<FakePeer>(kAddress3,
1305                                            dispatcher(),
1306                                            /*connectable=*/false,
1307                                            /*scannable=*/false);
1308     peer->set_directed_advertising_enabled(true);
1309     test_device()->AddPeer(std::move(peer));
1310   }
1311   // Address 4: directed connectable; added to cache below
1312   {
1313     auto peer = std::make_unique<FakePeer>(kAddress4,
1314                                            dispatcher(),
1315                                            /*connectable=*/true,
1316                                            /*scannable=*/false);
1317     peer->set_directed_advertising_enabled(true);
1318     test_device()->AddPeer(std::move(peer));
1319   }
1320   // Address 5: directed connectable; NOT in cache
1321   {
1322     auto peer = std::make_unique<FakePeer>(kAddress5,
1323                                            dispatcher(),
1324                                            /*connectable=*/true,
1325                                            /*scannable=*/false);
1326     peer->set_directed_advertising_enabled(true);
1327     test_device()->AddPeer(std::move(peer));
1328   }
1329 
1330   // Add cache entries for addresses 0, 2, 3, and 4. The callback should only
1331   // run for addresses 0 and 4 as the only known connectable peers. All other
1332   // advertisements should be ignored.
1333   auto address0_id =
1334       peer_cache()->NewPeer(kAddress0, /*connectable=*/true)->identifier();
1335   peer_cache()->NewPeer(kAddress2, /*connectable=*/false);
1336   peer_cache()->NewPeer(kAddress3, /*connectable=*/false);
1337   auto address4_id =
1338       peer_cache()->NewPeer(kAddress4, /*connectable=*/true)->identifier();
1339   EXPECT_EQ(4u, peer_cache()->count());
1340 
1341   int count = 0;
1342   discovery_manager()->set_peer_connectable_callback([&](Peer* peer) {
1343     ASSERT_TRUE(peer);
1344     auto id = peer->identifier();
1345     count++;
1346     EXPECT_TRUE(id == address0_id || id == address4_id) << id.ToString();
1347   });
1348   auto session = StartDiscoverySession(/*active=*/false);
1349   RunUntilIdle();
1350   EXPECT_EQ(2, count);
1351 
1352   // No new remote peer cache entries should have been created.
1353   EXPECT_EQ(4u, peer_cache()->count());
1354 }
1355 
TEST_F(LowEnergyDiscoveryManagerTest,PassiveScanPeriodRestart)1356 TEST_F(LowEnergyDiscoveryManagerTest, PassiveScanPeriodRestart) {
1357   discovery_manager()->set_scan_period(kTestScanPeriod);
1358   auto session = StartDiscoverySession(/*active=*/false);
1359 
1360   // The scan state should transition to enabled.
1361   RunUntilIdle();
1362   EXPECT_TRUE(scan_enabled());
1363   ASSERT_EQ(1u, scan_states().size());
1364   EXPECT_TRUE(test_device()->le_scan_state().enabled);
1365 
1366   // End the scan period by advancing time.
1367   RunFor(kTestScanPeriod);
1368   EXPECT_TRUE(test_device()->le_scan_state().enabled);
1369   EXPECT_EQ(pw::bluetooth::emboss::LEScanType::PASSIVE,
1370             test_device()->le_scan_state().scan_type);
1371   EXPECT_THAT(scan_states(), ::testing::ElementsAre(true, false, true));
1372 }
1373 
TEST_F(LowEnergyDiscoveryManagerTest,PauseActiveDiscoveryTwiceKeepsScanningDisabledUntilBothPauseTokensDestroyed)1374 TEST_F(
1375     LowEnergyDiscoveryManagerTest,
1376     PauseActiveDiscoveryTwiceKeepsScanningDisabledUntilBothPauseTokensDestroyed) {
1377   auto session = StartDiscoverySession();
1378   EXPECT_TRUE(scan_enabled());
1379 
1380   std::optional<PauseToken> pause_0 = discovery_manager()->PauseDiscovery();
1381   RunUntilIdle();
1382   EXPECT_FALSE(scan_enabled());
1383   EXPECT_TRUE(discovery_manager()->discovering());
1384 
1385   std::optional<PauseToken> pause_1 = discovery_manager()->PauseDiscovery();
1386   RunUntilIdle();
1387   EXPECT_FALSE(scan_enabled());
1388   EXPECT_TRUE(discovery_manager()->discovering());
1389 
1390   pause_0.reset();
1391   RunUntilIdle();
1392   EXPECT_FALSE(scan_enabled());
1393   EXPECT_TRUE(discovery_manager()->discovering());
1394 
1395   pause_1.reset();
1396   RunUntilIdle();
1397   EXPECT_TRUE(scan_enabled());
1398   EXPECT_TRUE(discovery_manager()->discovering());
1399 }
1400 
TEST_F(LowEnergyDiscoveryManagerTest,EnablePassiveScanAfterPausing)1401 TEST_F(LowEnergyDiscoveryManagerTest, EnablePassiveScanAfterPausing) {
1402   std::optional<PauseToken> pause = discovery_manager()->PauseDiscovery();
1403   RunUntilIdle();
1404   EXPECT_FALSE(scan_enabled());
1405 
1406   std::unique_ptr<LowEnergyDiscoverySession> session;
1407   discovery_manager()->StartDiscovery(
1408       /*active=*/false, {}, [&](auto cb_session) {
1409         session = std::move(cb_session);
1410       });
1411   RunUntilIdle();
1412   EXPECT_FALSE(scan_enabled());
1413   EXPECT_FALSE(session);
1414 
1415   pause.reset();
1416   RunUntilIdle();
1417   EXPECT_TRUE(scan_enabled());
1418 }
1419 
TEST_F(LowEnergyDiscoveryManagerTest,StartActiveScanAfterPausing)1420 TEST_F(LowEnergyDiscoveryManagerTest, StartActiveScanAfterPausing) {
1421   std::optional<PauseToken> pause = discovery_manager()->PauseDiscovery();
1422   RunUntilIdle();
1423   EXPECT_FALSE(scan_enabled());
1424 
1425   std::unique_ptr<LowEnergyDiscoverySession> session;
1426   discovery_manager()->StartDiscovery(
1427       /*active=*/true, {}, [&](auto cb_session) {
1428         session = std::move(cb_session);
1429       });
1430   RunUntilIdle();
1431   EXPECT_FALSE(scan_enabled());
1432   EXPECT_FALSE(session);
1433 
1434   pause.reset();
1435   RunUntilIdle();
1436   EXPECT_TRUE(scan_enabled());
1437   EXPECT_TRUE(session);
1438 }
1439 
TEST_F(LowEnergyDiscoveryManagerTest,PauseDiscoveryJustBeforeScanComplete)1440 TEST_F(LowEnergyDiscoveryManagerTest, PauseDiscoveryJustBeforeScanComplete) {
1441   discovery_manager()->set_scan_period(kTestScanPeriod);
1442 
1443   auto session = StartDiscoverySession();
1444   EXPECT_TRUE(scan_enabled());
1445 
1446   // Pause discovery in FakeController scan state callback to ensure it is
1447   // called just before kComplete status is received. This will be the 2nd scan
1448   // state change because it is started above and then stopped by the scan
1449   // period ending below.
1450   std::optional<PauseToken> pause;
1451   set_scan_state_handler(
1452       2, [this, &pause]() { pause = discovery_manager()->PauseDiscovery(); });
1453 
1454   RunFor(kTestScanPeriod);
1455   EXPECT_TRUE(pause.has_value());
1456   EXPECT_EQ(scan_states().size(), 2u);
1457   EXPECT_FALSE(scan_enabled());
1458 }
1459 
TEST_F(LowEnergyDiscoveryManagerTest,PauseDiscoveryJustBeforeScanStopped)1460 TEST_F(LowEnergyDiscoveryManagerTest, PauseDiscoveryJustBeforeScanStopped) {
1461   auto session = StartDiscoverySession();
1462   EXPECT_TRUE(scan_enabled());
1463 
1464   // Pause discovery in FakeController scan state callback to ensure it is
1465   // called just before kStopped status is received. This will be the 2nd scan
1466   // state change because it is started above and then stopped by the session
1467   // being destroyed below.
1468   std::optional<PauseToken> pause;
1469   set_scan_state_handler(
1470       2, [this, &pause]() { pause = discovery_manager()->PauseDiscovery(); });
1471 
1472   session.reset();
1473   RunUntilIdle();
1474   EXPECT_TRUE(pause.has_value());
1475   EXPECT_EQ(scan_states().size(), 2u);
1476   EXPECT_FALSE(scan_enabled());
1477 }
1478 
TEST_F(LowEnergyDiscoveryManagerTest,PauseJustBeforeScanActive)1479 TEST_F(LowEnergyDiscoveryManagerTest, PauseJustBeforeScanActive) {
1480   // Pause discovery in FakeController scan state callback to ensure it is
1481   // called just before kActive status is received. This will be the first scan
1482   // state change.
1483   std::optional<PauseToken> pause;
1484   set_scan_state_handler(
1485       1, [this, &pause]() { pause = discovery_manager()->PauseDiscovery(); });
1486 
1487   std::unique_ptr<LowEnergyDiscoverySession> session;
1488   discovery_manager()->StartDiscovery(
1489       /*active=*/true, {}, [&](auto cb_session) {
1490         session = std::move(cb_session);
1491       });
1492 
1493   // The scan should be canceled.
1494   RunUntilIdle();
1495   EXPECT_FALSE(session);
1496   EXPECT_TRUE(pause.has_value());
1497   EXPECT_EQ(scan_states().size(), 2u);
1498   EXPECT_FALSE(scan_enabled());
1499   EXPECT_FALSE(discovery_manager()->discovering());
1500 
1501   // Resume discovery.
1502   pause.reset();
1503   RunUntilIdle();
1504   EXPECT_TRUE(session);
1505   EXPECT_TRUE(scan_enabled());
1506   EXPECT_TRUE(discovery_manager()->discovering());
1507 }
1508 
TEST_F(LowEnergyDiscoveryManagerTest,PauseJustBeforeScanPassive)1509 TEST_F(LowEnergyDiscoveryManagerTest, PauseJustBeforeScanPassive) {
1510   // Pause discovery in FakeController scan state callback to ensure it is
1511   // called just before kPassive status is received. This will be the first scan
1512   // state change.
1513   std::optional<PauseToken> pause;
1514   set_scan_state_handler(
1515       1, [this, &pause]() { pause = discovery_manager()->PauseDiscovery(); });
1516 
1517   std::unique_ptr<LowEnergyDiscoverySession> session;
1518   discovery_manager()->StartDiscovery(
1519       /*active=*/false, {}, [&](auto cb_session) {
1520         session = std::move(cb_session);
1521       });
1522 
1523   // The scan should be canceled.
1524   RunUntilIdle();
1525   EXPECT_FALSE(session);
1526   EXPECT_TRUE(pause.has_value());
1527   EXPECT_EQ(scan_states().size(), 2u);
1528   EXPECT_FALSE(scan_enabled());
1529 
1530   // Resume scan.
1531   pause.reset();
1532   RunUntilIdle();
1533   EXPECT_TRUE(scan_enabled());
1534 }
1535 
TEST_F(LowEnergyDiscoveryManagerTest,StartActiveScanWhilePassiveScanStoppingBetweenScanPeriods)1536 TEST_F(LowEnergyDiscoveryManagerTest,
1537        StartActiveScanWhilePassiveScanStoppingBetweenScanPeriods) {
1538   discovery_manager()->set_scan_period(kTestScanPeriod);
1539 
1540   auto passive_session = StartDiscoverySession(/*active=*/false);
1541 
1542   std::unique_ptr<LowEnergyDiscoverySession> active_session;
1543   set_scan_state_handler(2, [this, &active_session]() {
1544     discovery_manager()->StartDiscovery(
1545         /*active=*/true, {}, [&active_session](auto session) {
1546           active_session = std::move(session);
1547         });
1548   });
1549   RunFor(kTestScanPeriod);
1550   EXPECT_TRUE(test_device()->le_scan_state().enabled);
1551   EXPECT_EQ(pw::bluetooth::emboss::LEScanType::ACTIVE,
1552             test_device()->le_scan_state().scan_type);
1553   EXPECT_THAT(scan_states(), ::testing::ElementsAre(true, false, true));
1554 }
1555 
TEST_F(LowEnergyDiscoveryManagerTest,StopSessionInsideOfResultCallbackDoesNotCrash)1556 TEST_F(LowEnergyDiscoveryManagerTest,
1557        StopSessionInsideOfResultCallbackDoesNotCrash) {
1558   auto session = StartDiscoverySession(/*active=*/false);
1559   auto result_cb = [&session](const auto&) { session->Stop(); };
1560   session->SetResultCallback(std::move(result_cb));
1561   RunUntilIdle();
1562 
1563   AddFakePeers();
1564   RunUntilIdle();
1565 }
1566 
TEST_F(LowEnergyDiscoveryManagerTest,PeerChangesFromNonConnectableToConnectable)1567 TEST_F(LowEnergyDiscoveryManagerTest,
1568        PeerChangesFromNonConnectableToConnectable) {
1569   test_device()->AddPeer(std::make_unique<FakePeer>(
1570       kAddress0, dispatcher(), /*connectable=*/false));
1571 
1572   std::unique_ptr<LowEnergyDiscoverySession> session;
1573   discovery_manager()->StartDiscovery(
1574       /*active=*/true, {}, [&session](auto cb_session) {
1575         session = std::move(cb_session);
1576       });
1577 
1578   RunUntilIdle();
1579   EXPECT_TRUE(scan_enabled());
1580   auto peer = peer_cache()->FindByAddress(kAddress0);
1581   ASSERT_TRUE(peer);
1582   EXPECT_FALSE(peer->connectable());
1583 
1584   // Make peer connectable.
1585   test_device()->RemovePeer(kAddress0);
1586   test_device()->AddPeer(std::make_unique<FakePeer>(
1587       kAddress0, dispatcher(), /*connectable=*/true));
1588 
1589   RunUntilIdle();
1590   peer = peer_cache()->FindByAddress(kAddress0);
1591   ASSERT_TRUE(peer);
1592   EXPECT_TRUE(peer->connectable());
1593 
1594   // Ensure peer stays connectable after non-connectable advertisement.
1595   test_device()->RemovePeer(kAddress0);
1596   test_device()->AddPeer(std::make_unique<FakePeer>(
1597       kAddress0, dispatcher(), /*connectable=*/false));
1598 
1599   RunUntilIdle();
1600   peer = peer_cache()->FindByAddress(kAddress0);
1601   ASSERT_TRUE(peer);
1602   EXPECT_TRUE(peer->connectable());
1603 }
1604 
1605 #ifndef NINSPECT
TEST_F(LowEnergyDiscoveryManagerTest,Inspect)1606 TEST_F(LowEnergyDiscoveryManagerTest, Inspect) {
1607   // Ensure node exists before testing properties.
1608   ASSERT_THAT(InspectHierarchy(),
1609               AllOf(ChildrenMatch(ElementsAre(NodeMatches(
1610                   AllOf(NameMatches(std::string(kInspectNodeName))))))));
1611   EXPECT_THAT(InspectProperties(),
1612               UnorderedElementsAre(StringIs("state", "Idle"),
1613                                    IntIs("paused", 0),
1614                                    UintIs("failed_count", 0u),
1615                                    DoubleIs("scan_interval_ms", 0.0),
1616                                    DoubleIs("scan_window_ms", 0.0)));
1617 
1618   std::unique_ptr<LowEnergyDiscoverySession> passive_session;
1619   discovery_manager()->StartDiscovery(
1620       /*active=*/false, {}, [&](auto cb_session) {
1621         PW_CHECK(cb_session);
1622         passive_session = std::move(cb_session);
1623       });
1624   EXPECT_THAT(InspectProperties(),
1625               ::testing::IsSupersetOf(
1626                   {StringIs("state", "Starting"),
1627                    DoubleIs("scan_interval_ms", ::testing::Gt(0.0)),
1628                    DoubleIs("scan_window_ms", ::testing::Gt(0.0))}));
1629 
1630   RunUntilIdle();
1631   EXPECT_THAT(InspectProperties(),
1632               ::testing::IsSupersetOf(
1633                   {StringIs("state", "Passive"),
1634                    DoubleIs("scan_interval_ms", ::testing::Gt(0.0)),
1635                    DoubleIs("scan_window_ms", ::testing::Gt(0.0))}));
1636 
1637   {
1638     auto pause_token = discovery_manager()->PauseDiscovery();
1639     EXPECT_THAT(InspectProperties(),
1640                 ::testing::IsSupersetOf(
1641                     {StringIs("state", "Stopping"), IntIs("paused", 1)}));
1642   }
1643 
1644   auto active_session = StartDiscoverySession();
1645   EXPECT_THAT(InspectProperties(),
1646               ::testing::IsSupersetOf(
1647                   {StringIs("state", "Active"),
1648                    DoubleIs("scan_interval_ms", ::testing::Gt(0.0)),
1649                    DoubleIs("scan_window_ms", ::testing::Gt(0.0))}));
1650 
1651   passive_session.reset();
1652   active_session.reset();
1653   EXPECT_THAT(InspectProperties(),
1654               ::testing::IsSupersetOf({StringIs("state", "Stopping")}));
1655   RunUntilIdle();
1656   EXPECT_THAT(InspectProperties(),
1657               ::testing::IsSupersetOf({StringIs("state", "Idle")}));
1658 
1659   // Cause discovery to fail.
1660   test_device()->SetDefaultResponseStatus(
1661       hci_spec::kLESetScanEnable,
1662       pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
1663   discovery_manager()->StartDiscovery(
1664       /*active=*/true, {}, [](auto session) { EXPECT_FALSE(session); });
1665   RunUntilIdle();
1666   EXPECT_THAT(InspectProperties(),
1667               ::testing::IsSupersetOf({UintIs("failed_count", 1u)}));
1668 }
1669 #endif  // NINSPECT
1670 
TEST_F(LowEnergyDiscoveryManagerTest,SetResultCallbackIgnoresRemovedPeers)1671 TEST_F(LowEnergyDiscoveryManagerTest, SetResultCallbackIgnoresRemovedPeers) {
1672   auto fake_peer_0 = std::make_unique<FakePeer>(kAddress0, dispatcher());
1673   test_device()->AddPeer(std::move(fake_peer_0));
1674   Peer* peer_0 = peer_cache()->NewPeer(kAddress0, /*connectable=*/true);
1675   PeerId peer_id_0 = peer_0->identifier();
1676 
1677   auto fake_peer_1 = std::make_unique<FakePeer>(kAddress1, dispatcher());
1678   test_device()->AddPeer(std::move(fake_peer_1));
1679   Peer* peer_1 = peer_cache()->NewPeer(kAddress1, /*connectable=*/true);
1680   PeerId peer_id_1 = peer_1->identifier();
1681 
1682   // Start active session so that results get cached.
1683   auto session = StartDiscoverySession();
1684 
1685   std::unordered_map<PeerId, int> result_counts;
1686   session->SetResultCallback(
1687       [&](const Peer& peer) { result_counts[peer.identifier()]++; });
1688   RunUntilIdle();
1689   EXPECT_EQ(result_counts[peer_id_0], 1);
1690   EXPECT_EQ(result_counts[peer_id_1], 1);
1691 
1692   // Remove peer_0 to make the cached result stale. The result callback should
1693   // not be called again for peer_0.
1694   ASSERT_TRUE(peer_cache()->RemoveDisconnectedPeer(peer_0->identifier()));
1695   session->SetResultCallback(
1696       [&](const Peer& peer) { result_counts[peer.identifier()]++; });
1697   RunUntilIdle();
1698   EXPECT_EQ(result_counts[peer_id_0], 1);
1699   EXPECT_EQ(result_counts[peer_id_1], 2);
1700 }
1701 
1702 }  // namespace
1703 }  // namespace bt::gap
1704