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