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/hci/fake_local_address_delegate.h"
16 #include "pw_bluetooth_sapphire/internal/host/hci/legacy_low_energy_scanner.h"
17 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
18 #include "pw_bluetooth_sapphire/internal/host/testing/fake_controller.h"
19 #include "pw_bluetooth_sapphire/internal/host/testing/fake_peer.h"
20
21 // LowEnergyScanner has many potential subclasses (e.g. LegacyLowEnergyScanner,
22 // ExtendedLowEnergyScanner, etc). The unique features of these subclasses are
23 // tested individually in their own unittest files. However, there are some
24 // common features that all LowEnergyScanners should follow. This test file
25 // implements a type parameterized test to exercise those common features.
26 //
27 // If you add a new subclass of LowEnergyScanner in the future, make sure to add
28 // its type to the list of types below (in the TYPED_TEST_SUITE) so that its
29 // common features are exercised as well.
30
31 namespace bt::hci {
32
33 using bt::testing::FakeController;
34 using bt::testing::FakePeer;
35 using TestingBase = bt::testing::FakeDispatcherControllerTest<FakeController>;
36
37 constexpr pw::chrono::SystemClock::duration kScanPeriod =
38 std::chrono::seconds(10);
39 constexpr pw::chrono::SystemClock::duration kPwScanPeriod =
40 std::chrono::seconds(10);
41 constexpr pw::chrono::SystemClock::duration kScanResponseTimeout =
42 std::chrono::seconds(2);
43 constexpr pw::chrono::SystemClock::duration kPwScanResponseTimeout =
44 std::chrono::seconds(2);
45
46 // The unit tests below assume that the scan period is longer than the scan
47 // response timeout when exercising timeout expiration.
48 static_assert(kScanResponseTimeout < kScanPeriod,
49 "expected a smaller scan response timeout for testing");
50
51 const StaticByteBuffer kPlainAdvDataBytes('T', 'e', 's', 't');
52 const StaticByteBuffer kPlainScanRspBytes('D', 'a', 't', 'a');
53
54 constexpr char kPlainAdvData[] = "Test";
55 constexpr char kPlainScanRsp[] = "Data";
56 constexpr char kAdvDataAndScanRsp[] = "TestData";
57
58 const DeviceAddress kPublicAddress1(DeviceAddress::Type::kLEPublic, {1});
59 const DeviceAddress kPublicAddress2(DeviceAddress::Type::kLEPublic, {2});
60
61 const DeviceAddress kRandomAddress1(DeviceAddress::Type::kLERandom, {3});
62 const DeviceAddress kRandomAddress2(DeviceAddress::Type::kLERandom, {4});
63 const DeviceAddress kRandomAddress3(DeviceAddress::Type::kLERandom, {5});
64 const DeviceAddress kRandomAddress4(DeviceAddress::Type::kLERandom, {6});
65
66 template <typename T>
67 class LowEnergyScannerTest : public TestingBase,
68 public LowEnergyScanner::Delegate {
69 public:
70 LowEnergyScannerTest() = default;
71 ~LowEnergyScannerTest() override = default;
72
73 protected:
SetUp()74 void SetUp() override {
75 TestingBase::SetUp();
76
77 FakeController::Settings settings;
78 settings.ApplyLegacyLEConfig();
79 this->test_device()->set_settings(settings);
80
81 scanner_ = std::unique_ptr<T>(CreateScannerInternal());
82 scanner_->set_delegate(this);
83 }
84
TearDown()85 void TearDown() override {
86 scanner_ = nullptr;
87 this->test_device()->Stop();
88 TestingBase::TearDown();
89 }
90
91 template <bool same = std::is_same_v<T, LegacyLowEnergyScanner>>
CreateScannerInternal()92 std::enable_if_t<same, LegacyLowEnergyScanner>* CreateScannerInternal() {
93 return new LegacyLowEnergyScanner(
94 fake_address_delegate(), transport()->GetWeakPtr(), dispatcher());
95 }
96
97 using PeerFoundCallback =
98 fit::function<void(const LowEnergyScanResult&, const ByteBuffer&)>;
set_peer_found_callback(PeerFoundCallback cb)99 void set_peer_found_callback(PeerFoundCallback cb) {
100 peer_found_cb_ = std::move(cb);
101 }
102
103 using DirectedAdvCallback = fit::function<void(const LowEnergyScanResult&)>;
set_directed_adv_callback(DirectedAdvCallback cb)104 void set_directed_adv_callback(DirectedAdvCallback cb) {
105 directed_adv_cb_ = std::move(cb);
106 }
107
StartScan(bool active,pw::chrono::SystemClock::duration period=LowEnergyScanner::kPeriodInfinite)108 bool StartScan(bool active,
109 pw::chrono::SystemClock::duration period =
110 LowEnergyScanner::kPeriodInfinite) {
111 LowEnergyScanner::ScanOptions options{
112 .active = active,
113 .filter_duplicates = true,
114 .period = period,
115 .scan_response_timeout = kPwScanResponseTimeout};
116 return scanner()->StartScan(
117 options, [this](auto status) { last_scan_status_ = status; });
118 }
119
120 // LowEnergyScanner::Observer override:
OnPeerFound(const LowEnergyScanResult & result,const ByteBuffer & data)121 void OnPeerFound(const LowEnergyScanResult& result,
122 const ByteBuffer& data) override {
123 if (peer_found_cb_) {
124 peer_found_cb_(result, data);
125 }
126 }
127
128 // LowEnergyScanner::Observer override:
OnDirectedAdvertisement(const LowEnergyScanResult & result)129 void OnDirectedAdvertisement(const LowEnergyScanResult& result) override {
130 if (directed_adv_cb_) {
131 directed_adv_cb_(result);
132 }
133 }
134
135 // Adds 6 fake peers using kAddress[0-5] above.
AddFakePeers()136 void AddFakePeers() {
137 // Generates ADV_IND, scan response is reported in a single HCI event.
138 auto fake_peer =
139 std::make_unique<FakePeer>(kPublicAddress1, dispatcher(), true, true);
140 fake_peer->set_advertising_data(kPlainAdvDataBytes);
141 fake_peer->set_scan_response(/*should_batch_reports=*/true,
142 kPlainScanRspBytes);
143 test_device()->AddPeer(std::move(fake_peer));
144
145 // Generates ADV_SCAN_IND, scan response is reported over multiple HCI
146 // events.
147 fake_peer =
148 std::make_unique<FakePeer>(kRandomAddress1, dispatcher(), false, true);
149 fake_peer->set_advertising_data(kPlainAdvDataBytes);
150 fake_peer->set_scan_response(/*should_batch_reports=*/false,
151 kPlainScanRspBytes);
152 test_device()->AddPeer(std::move(fake_peer));
153
154 // Generates ADV_IND, empty scan response is reported over multiple HCI
155 // events.
156 fake_peer =
157 std::make_unique<FakePeer>(kPublicAddress2, dispatcher(), true, true);
158 fake_peer->set_advertising_data(kPlainAdvDataBytes);
159 fake_peer->set_scan_response(/*should_batch_reports=*/false,
160 DynamicByteBuffer());
161 test_device()->AddPeer(std::move(fake_peer));
162
163 // Generates ADV_IND, empty adv data and non-empty scan response is reported
164 // over multiple HCI events.
165 fake_peer =
166 std::make_unique<FakePeer>(kRandomAddress2, dispatcher(), true, true);
167 fake_peer->set_scan_response(/*should_batch_reports=*/false,
168 kPlainScanRspBytes);
169 test_device()->AddPeer(std::move(fake_peer));
170
171 // Generates ADV_IND, a scan response is never sent even though ADV_IND is
172 // scannable.
173 fake_peer =
174 std::make_unique<FakePeer>(kRandomAddress3, dispatcher(), true, false);
175 fake_peer->set_advertising_data(kPlainAdvDataBytes);
176 test_device()->AddPeer(std::move(fake_peer));
177
178 // Generates ADV_NONCONN_IND
179 fake_peer =
180 std::make_unique<FakePeer>(kRandomAddress4, dispatcher(), false, false);
181 fake_peer->set_advertising_data(kPlainAdvDataBytes);
182 test_device()->AddPeer(std::move(fake_peer));
183 }
184
scanner() const185 LowEnergyScanner* scanner() const { return scanner_.get(); }
fake_address_delegate()186 FakeLocalAddressDelegate* fake_address_delegate() {
187 return &fake_address_delegate_;
188 }
189
last_scan_status() const190 LowEnergyScanner::ScanStatus last_scan_status() const {
191 return last_scan_status_;
192 }
193
194 private:
195 PeerFoundCallback peer_found_cb_;
196 DirectedAdvCallback directed_adv_cb_;
197 FakeLocalAddressDelegate fake_address_delegate_{dispatcher()};
198 std::unique_ptr<LowEnergyScanner> scanner_;
199
200 LowEnergyScanner::ScanStatus last_scan_status_;
201
202 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyScannerTest);
203 };
204
205 using Implementations = ::testing::Types<LegacyLowEnergyScanner>;
206 TYPED_TEST_SUITE(LowEnergyScannerTest, Implementations);
207
TYPED_TEST(LowEnergyScannerTest,StartScanHCIErrors)208 TYPED_TEST(LowEnergyScannerTest, StartScanHCIErrors) {
209 EXPECT_TRUE(this->scanner()->IsIdle());
210 EXPECT_FALSE(this->scanner()->IsScanning());
211 EXPECT_FALSE(this->test_device()->le_scan_state().enabled);
212
213 // Set Scan Parameters will fail.
214 this->test_device()->SetDefaultResponseStatus(
215 hci_spec::kLESetScanParameters,
216 pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE);
217 EXPECT_EQ(0, this->test_device()->le_scan_state().scan_interval);
218
219 EXPECT_TRUE(this->StartScan(false));
220 EXPECT_EQ(LowEnergyScanner::State::kInitiating, this->scanner()->state());
221
222 // Calling StartScan() should fail as the state is not kIdle.
223 EXPECT_FALSE(this->StartScan(false));
224 this->RunUntilIdle();
225
226 // Status should be failure and the scan parameters shouldn't have applied.
227 EXPECT_EQ(LowEnergyScanner::ScanStatus::kFailed, this->last_scan_status());
228 EXPECT_EQ(0, this->test_device()->le_scan_state().scan_interval);
229 EXPECT_FALSE(this->test_device()->le_scan_state().enabled);
230 EXPECT_TRUE(this->scanner()->IsIdle());
231 EXPECT_FALSE(this->scanner()->IsScanning());
232
233 // Set Scan Parameters will succeed but Set Scan Enable will fail.
234 this->test_device()->ClearDefaultResponseStatus(
235 hci_spec::kLESetScanParameters);
236 this->test_device()->SetDefaultResponseStatus(
237 hci_spec::kLESetScanEnable,
238 pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE);
239
240 EXPECT_TRUE(this->StartScan(false));
241 EXPECT_EQ(LowEnergyScanner::State::kInitiating, this->scanner()->state());
242 this->RunUntilIdle();
243
244 // Status should be failure but the scan parameters should have applied.
245 EXPECT_EQ(LowEnergyScanner::ScanStatus::kFailed, this->last_scan_status());
246 EXPECT_EQ(hci_spec::defaults::kLEScanInterval,
247 this->test_device()->le_scan_state().scan_interval);
248 EXPECT_EQ(hci_spec::defaults::kLEScanWindow,
249 this->test_device()->le_scan_state().scan_window);
250 EXPECT_EQ(pw::bluetooth::emboss::LEScanFilterPolicy::BASIC_UNFILTERED,
251 this->test_device()->le_scan_state().filter_policy);
252 EXPECT_FALSE(this->test_device()->le_scan_state().enabled);
253 EXPECT_TRUE(this->scanner()->IsIdle());
254 EXPECT_FALSE(this->scanner()->IsScanning());
255 }
256
TYPED_TEST(LowEnergyScannerTest,StartScan)257 TYPED_TEST(LowEnergyScannerTest, StartScan) {
258 EXPECT_TRUE(this->scanner()->IsIdle());
259 EXPECT_FALSE(this->scanner()->IsScanning());
260 EXPECT_FALSE(this->test_device()->le_scan_state().enabled);
261
262 EXPECT_TRUE(this->StartScan(true, kPwScanPeriod));
263 EXPECT_EQ(LowEnergyScanner::State::kInitiating, this->scanner()->state());
264 this->RunUntilIdle();
265
266 // Scan should have started.
267 EXPECT_EQ(LowEnergyScanner::ScanStatus::kActive, this->last_scan_status());
268 EXPECT_EQ(hci_spec::defaults::kLEScanInterval,
269 this->test_device()->le_scan_state().scan_interval);
270 EXPECT_EQ(hci_spec::defaults::kLEScanWindow,
271 this->test_device()->le_scan_state().scan_window);
272 EXPECT_EQ(pw::bluetooth::emboss::LEScanFilterPolicy::BASIC_UNFILTERED,
273 this->test_device()->le_scan_state().filter_policy);
274 EXPECT_EQ(pw::bluetooth::emboss::LEScanType::ACTIVE,
275 this->test_device()->le_scan_state().scan_type);
276 EXPECT_TRUE(this->test_device()->le_scan_state().filter_duplicates);
277 EXPECT_TRUE(this->test_device()->le_scan_state().enabled);
278 EXPECT_EQ(LowEnergyScanner::State::kActiveScanning, this->scanner()->state());
279 EXPECT_TRUE(this->scanner()->IsScanning());
280
281 // Calling StartScan should fail as a scan is already in progress.
282 EXPECT_FALSE(this->StartScan(true));
283
284 // After 10 s (kScanPeriod) the scan should stop by itself.
285 this->RunFor(kScanPeriod);
286
287 EXPECT_EQ(LowEnergyScanner::ScanStatus::kComplete, this->last_scan_status());
288 EXPECT_FALSE(this->test_device()->le_scan_state().enabled);
289 EXPECT_TRUE(this->scanner()->IsIdle());
290 EXPECT_FALSE(this->scanner()->IsScanning());
291 }
292
TYPED_TEST(LowEnergyScannerTest,StopScan)293 TYPED_TEST(LowEnergyScannerTest, StopScan) {
294 EXPECT_TRUE(this->scanner()->IsIdle());
295 EXPECT_FALSE(this->scanner()->IsScanning());
296 EXPECT_FALSE(this->test_device()->le_scan_state().enabled);
297
298 // Calling StopScan should fail while a scan is not in progress.
299 EXPECT_FALSE(this->scanner()->StopScan());
300
301 // Pass a long scan period value. This should not matter as we will terminate
302 // the scan directly.
303 EXPECT_TRUE(this->StartScan(true, kPwScanPeriod * 10u));
304 EXPECT_EQ(LowEnergyScanner::State::kInitiating, this->scanner()->state());
305 this->RunUntilIdle();
306
307 // Scan should have started.
308 EXPECT_EQ(LowEnergyScanner::ScanStatus::kActive, this->last_scan_status());
309 EXPECT_TRUE(this->test_device()->le_scan_state().enabled);
310 EXPECT_EQ(LowEnergyScanner::State::kActiveScanning, this->scanner()->state());
311 EXPECT_TRUE(this->scanner()->IsScanning());
312
313 // StopScan() should terminate the scan session and the status should be
314 // kStopped.
315 EXPECT_TRUE(this->scanner()->StopScan());
316 this->RunUntilIdle();
317
318 EXPECT_EQ(LowEnergyScanner::ScanStatus::kStopped, this->last_scan_status());
319 EXPECT_FALSE(this->test_device()->le_scan_state().enabled);
320 EXPECT_TRUE(this->scanner()->IsIdle());
321 EXPECT_FALSE(this->scanner()->IsScanning());
322 }
323
TYPED_TEST(LowEnergyScannerTest,StopScanWhileInitiating)324 TYPED_TEST(LowEnergyScannerTest, StopScanWhileInitiating) {
325 EXPECT_TRUE(this->scanner()->IsIdle());
326 EXPECT_FALSE(this->scanner()->IsScanning());
327 EXPECT_FALSE(this->test_device()->le_scan_state().enabled);
328
329 EXPECT_TRUE(this->StartScan(true));
330 EXPECT_EQ(LowEnergyScanner::State::kInitiating, this->scanner()->state());
331
332 // Call StopScan(). This should cancel the HCI command sequence set up by
333 // StartScan() so that the it never completes. The HCI_LE_Set_Scan_Parameters
334 // command *may* get sent but the scan should never get enabled.
335 EXPECT_TRUE(this->scanner()->StopScan());
336 this->RunUntilIdle();
337
338 EXPECT_EQ(LowEnergyScanner::ScanStatus::kStopped, this->last_scan_status());
339 EXPECT_FALSE(this->test_device()->le_scan_state().enabled);
340 EXPECT_TRUE(this->scanner()->IsIdle());
341 EXPECT_FALSE(this->scanner()->IsScanning());
342 }
343
TYPED_TEST(LowEnergyScannerTest,ScanResponseTimeout)344 TYPED_TEST(LowEnergyScannerTest, ScanResponseTimeout) {
345 constexpr pw::chrono::SystemClock::duration kHalfTimeout =
346 kScanResponseTimeout / 2;
347
348 std::unordered_set<DeviceAddress> results;
349 this->set_peer_found_callback([&](const auto& result, const auto& data) {
350 results.insert(result.address);
351 });
352
353 // Add a peer that sends a scan response and one that doesn't.
354 auto fake_peer = std::make_unique<FakePeer>(
355 kRandomAddress1, this->dispatcher(), false, true);
356 fake_peer->set_advertising_data(kPlainAdvDataBytes);
357 fake_peer->set_scan_response(/*should_batch_reports=*/false,
358 kPlainScanRspBytes);
359 this->test_device()->AddPeer(std::move(fake_peer));
360
361 fake_peer = std::make_unique<FakePeer>(
362 kRandomAddress2, this->dispatcher(), true, false);
363 fake_peer->set_advertising_data(kPlainAdvDataBytes);
364 this->test_device()->AddPeer(std::move(fake_peer));
365
366 EXPECT_TRUE(this->StartScan(true));
367 this->RunUntilIdle();
368 ASSERT_EQ(1u, results.size());
369 EXPECT_EQ(1u, results.count(kRandomAddress1));
370
371 // Advance the time but do not expire the timeout.
372 this->RunFor(kHalfTimeout);
373 ASSERT_EQ(1u, results.size());
374
375 // Add another peer that doesn't send a scan response after the kHalfTimeout
376 // delay. This is to test that a separate timeout is kept for every peer.
377 fake_peer = std::make_unique<FakePeer>(
378 kRandomAddress3, this->dispatcher(), true, false);
379 fake_peer->set_advertising_data(kPlainAdvDataBytes);
380 this->test_device()->AddPeer(std::move(fake_peer));
381
382 // Expire the first timeout.
383 this->RunFor(kHalfTimeout);
384 ASSERT_EQ(2u, results.size());
385 EXPECT_EQ(1u, results.count(kRandomAddress1));
386 EXPECT_EQ(1u, results.count(kRandomAddress2));
387
388 // Expire the second timeout.
389 this->RunFor(kHalfTimeout);
390 ASSERT_EQ(3u, results.size());
391 EXPECT_EQ(1u, results.count(kRandomAddress1));
392 EXPECT_EQ(1u, results.count(kRandomAddress2));
393 EXPECT_EQ(1u, results.count(kRandomAddress3));
394 }
395
TYPED_TEST(LowEnergyScannerTest,ActiveScanResults)396 TYPED_TEST(LowEnergyScannerTest, ActiveScanResults) {
397 // One of the 6 fake peers is scannable but never sends scan response
398 // packets. That peer doesn't get reported until the end of the scan period.
399 constexpr size_t kExpectedResultCount = 5u;
400
401 this->AddFakePeers();
402
403 std::map<DeviceAddress, std::pair<LowEnergyScanResult, std::string>> results;
404 this->set_peer_found_callback([&](const auto& result, const auto& data) {
405 results[result.address] = std::make_pair(result, data.ToString());
406 });
407
408 // Perform an active scan.
409 EXPECT_TRUE(this->StartScan(true, kPwScanPeriod));
410 EXPECT_EQ(LowEnergyScanner::State::kInitiating, this->scanner()->state());
411
412 this->RunUntilIdle();
413
414 ASSERT_EQ(kExpectedResultCount, results.size());
415
416 // Ending the scan period should notify Fake Peer #4.
417 this->RunFor(kScanPeriod);
418 EXPECT_EQ(LowEnergyScanner::ScanStatus::kComplete, this->last_scan_status());
419 ASSERT_EQ(kExpectedResultCount + 1, results.size());
420
421 // Verify the 6 results against the fake peers that were set up by
422 // this->AddFakePeers(). Since the scan period ended naturally,
423 // LowEnergyScanner should generate a peer found event for all pending reports
424 // even if a scan response was not received for a scannable peer (see Fake
425 // Peer 4, i.e. kRandomAddress3).
426
427 // Result 0 (ADV_IND)
428 {
429 const auto& iter = results.find(kPublicAddress1);
430 ASSERT_NE(iter, results.end());
431
432 const auto& result_pair = iter->second;
433 EXPECT_EQ(kAdvDataAndScanRsp, result_pair.second);
434 EXPECT_EQ(kPublicAddress1, result_pair.first.address);
435 EXPECT_TRUE(result_pair.first.connectable);
436 results.erase(iter);
437 }
438
439 // Result 1 (ADV_SCAN_IND)
440 {
441 const auto& iter = results.find(kRandomAddress1);
442 ASSERT_NE(iter, results.end());
443
444 const auto& result_pair = iter->second;
445 EXPECT_EQ(kAdvDataAndScanRsp, result_pair.second);
446 EXPECT_EQ(kRandomAddress1, result_pair.first.address);
447 EXPECT_FALSE(result_pair.first.connectable);
448 results.erase(iter);
449 }
450
451 // Result 2 (ADV_IND), empty scan response
452 {
453 const auto& iter = results.find(kPublicAddress2);
454 ASSERT_NE(iter, results.end());
455
456 const auto& result_pair = iter->second;
457 EXPECT_EQ(kPlainAdvData, result_pair.second);
458 EXPECT_EQ(kPublicAddress2, result_pair.first.address);
459 EXPECT_TRUE(result_pair.first.connectable);
460 results.erase(iter);
461 }
462
463 // Result 3 (ADV_IND), empty advertising data w/ scan response
464 {
465 const auto& iter = results.find(kRandomAddress2);
466 ASSERT_NE(iter, results.end());
467
468 const auto& result_pair = iter->second;
469 EXPECT_EQ(kPlainScanRsp, result_pair.second);
470 EXPECT_EQ(kRandomAddress2, result_pair.first.address);
471 EXPECT_TRUE(result_pair.first.connectable);
472 results.erase(iter);
473 }
474
475 // Result 4 (ADV_IND), no scan response
476 {
477 const auto& iter = results.find(kRandomAddress3);
478 ASSERT_NE(iter, results.end());
479
480 const auto& result_pair = iter->second;
481 EXPECT_EQ(kPlainAdvData, result_pair.second);
482 EXPECT_EQ(kRandomAddress3, result_pair.first.address);
483 EXPECT_TRUE(result_pair.first.connectable);
484 results.erase(iter);
485 }
486
487 // Result 5 (ADV_NONCONN_IND)
488 {
489 const auto& iter = results.find(kRandomAddress4);
490 ASSERT_NE(iter, results.end());
491
492 const auto& result_pair = iter->second;
493 EXPECT_EQ(kPlainAdvData, result_pair.second);
494 EXPECT_EQ(kRandomAddress4, result_pair.first.address);
495 EXPECT_FALSE(result_pair.first.connectable);
496 results.erase(iter);
497 }
498
499 // No other reports are expected
500 EXPECT_TRUE(results.empty());
501 }
502
TYPED_TEST(LowEnergyScannerTest,StopDuringActiveScan)503 TYPED_TEST(LowEnergyScannerTest, StopDuringActiveScan) {
504 this->AddFakePeers();
505
506 std::map<DeviceAddress, std::pair<LowEnergyScanResult, std::string>> results;
507 this->set_peer_found_callback(
508 [&results](const auto& result, const auto& data) {
509 results[result.address] = std::make_pair(result, data.ToString());
510 });
511
512 // Perform an active scan indefinitely. This means that the scan period will
513 // never complete by itself.
514 EXPECT_TRUE(this->StartScan(true));
515 EXPECT_EQ(LowEnergyScanner::State::kInitiating, this->scanner()->state());
516 this->RunUntilIdle();
517 EXPECT_EQ(LowEnergyScanner::State::kActiveScanning, this->scanner()->state());
518
519 // Run the loop until we've seen an event for the last peer that we
520 // added. Fake Peer kRandomAddress3 is scannable but it never sends a scan
521 // response so we expect that to remain in the scanner's pending reports list.
522 this->RunUntilIdle();
523 EXPECT_EQ(5u, results.size());
524 EXPECT_EQ(results.find(kRandomAddress3), results.end());
525
526 // Stop the scan. Since we are terminating the scan period early,
527 // LowEnergyScanner should not send a report for the pending peer.
528 EXPECT_TRUE(this->scanner()->StopScan());
529 this->RunUntilIdle();
530 EXPECT_TRUE(this->scanner()->IsIdle());
531
532 EXPECT_EQ(5u, results.size());
533 EXPECT_EQ(results.find(kRandomAddress3), results.end());
534 }
535
TYPED_TEST(LowEnergyScannerTest,PassiveScanResults)536 TYPED_TEST(LowEnergyScannerTest, PassiveScanResults) {
537 constexpr size_t kExpectedResultCount = 6u;
538 this->AddFakePeers();
539
540 std::map<DeviceAddress, std::pair<LowEnergyScanResult, std::string>> results;
541 this->set_peer_found_callback([&](const auto& result, const auto& data) {
542 results[result.address] = std::make_pair(result, data.ToString());
543 });
544
545 // Perform a passive scan.
546 EXPECT_TRUE(this->StartScan(false));
547
548 EXPECT_EQ(LowEnergyScanner::State::kInitiating, this->scanner()->state());
549
550 this->RunUntilIdle();
551 EXPECT_EQ(LowEnergyScanner::State::kPassiveScanning,
552 this->scanner()->state());
553 EXPECT_EQ(LowEnergyScanner::ScanStatus::kPassive, this->last_scan_status());
554 ASSERT_EQ(kExpectedResultCount, results.size());
555
556 // Verify the 6 results against the fake peers that were set up by
557 // this->AddFakePeers(). All Scan Response PDUs should have been ignored.
558
559 // Result 0
560 {
561 const auto& iter = results.find(kPublicAddress1);
562 ASSERT_NE(iter, results.end());
563
564 const auto& result_pair = iter->second;
565 EXPECT_EQ(kPlainAdvData, result_pair.second);
566 EXPECT_EQ(kPublicAddress1, result_pair.first.address);
567 EXPECT_TRUE(result_pair.first.connectable);
568 results.erase(iter);
569 }
570
571 // Result 1
572 {
573 const auto& iter = results.find(kRandomAddress1);
574 ASSERT_NE(iter, results.end());
575
576 const auto& result_pair = iter->second;
577 EXPECT_EQ(kPlainAdvData, result_pair.second);
578 EXPECT_EQ(kRandomAddress1, result_pair.first.address);
579 EXPECT_FALSE(result_pair.first.connectable);
580 results.erase(iter);
581 }
582
583 // Result 2
584 {
585 const auto& iter = results.find(kPublicAddress2);
586 ASSERT_NE(iter, results.end());
587
588 const auto& result_pair = iter->second;
589 EXPECT_EQ(kPlainAdvData, result_pair.second);
590 EXPECT_EQ(kPublicAddress2, result_pair.first.address);
591 EXPECT_TRUE(result_pair.first.connectable);
592 results.erase(iter);
593 }
594
595 // Result 3
596 {
597 const auto& iter = results.find(kRandomAddress2);
598 ASSERT_NE(iter, results.end());
599
600 const auto& result_pair = iter->second;
601 EXPECT_EQ("", result_pair.second);
602 EXPECT_EQ(kRandomAddress2, result_pair.first.address);
603 EXPECT_TRUE(result_pair.first.connectable);
604 results.erase(iter);
605 }
606
607 // Result 4
608 {
609 const auto& iter = results.find(kRandomAddress3);
610 ASSERT_NE(iter, results.end());
611
612 const auto& result_pair = iter->second;
613 EXPECT_EQ(kPlainAdvData, result_pair.second);
614 EXPECT_EQ(kRandomAddress3, result_pair.first.address);
615 EXPECT_TRUE(result_pair.first.connectable);
616 results.erase(iter);
617 }
618
619 // Result 5
620 {
621 const auto& iter = results.find(kRandomAddress4);
622 ASSERT_NE(iter, results.end());
623
624 const auto& result_pair = iter->second;
625 EXPECT_EQ(kPlainAdvData, result_pair.second);
626 EXPECT_EQ(kRandomAddress4, result_pair.first.address);
627 EXPECT_FALSE(result_pair.first.connectable);
628 results.erase(iter);
629 }
630
631 EXPECT_TRUE(results.empty());
632 }
633
TYPED_TEST(LowEnergyScannerTest,DirectedReport)634 TYPED_TEST(LowEnergyScannerTest, DirectedReport) {
635 const auto& kPublicUnresolved = kPublicAddress1;
636 const auto& kPublicResolved = kPublicAddress2;
637 const auto& kRandomUnresolved = kRandomAddress1;
638 const auto& kRandomResolved = kRandomAddress2;
639 constexpr size_t kExpectedResultCount = 4u;
640
641 // Unresolved public.
642 auto fake_peer = std::make_unique<FakePeer>(
643 kPublicUnresolved, this->dispatcher(), true, false);
644 fake_peer->set_directed_advertising_enabled(true);
645 this->test_device()->AddPeer(std::move(fake_peer));
646
647 // Unresolved random.
648 fake_peer = std::make_unique<FakePeer>(
649 kRandomUnresolved, this->dispatcher(), true, false);
650 fake_peer->set_directed_advertising_enabled(true);
651 this->test_device()->AddPeer(std::move(fake_peer));
652
653 // Resolved public.
654 fake_peer = std::make_unique<FakePeer>(
655 kPublicResolved, this->dispatcher(), true, false);
656 fake_peer->set_address_resolved(true);
657 fake_peer->set_directed_advertising_enabled(true);
658 this->test_device()->AddPeer(std::move(fake_peer));
659
660 // Resolved random.
661 fake_peer = std::make_unique<FakePeer>(
662 kRandomResolved, this->dispatcher(), true, false);
663 fake_peer->set_address_resolved(true);
664 fake_peer->set_directed_advertising_enabled(true);
665 this->test_device()->AddPeer(std::move(fake_peer));
666
667 std::unordered_map<DeviceAddress, LowEnergyScanResult> results;
668 this->set_directed_adv_callback(
669 [&](const auto& result) { results[result.address] = result; });
670
671 EXPECT_TRUE(this->StartScan(true));
672 EXPECT_EQ(LowEnergyScanner::State::kInitiating, this->scanner()->state());
673
674 this->RunUntilIdle();
675
676 ASSERT_EQ(LowEnergyScanner::ScanStatus::kActive, this->last_scan_status());
677 ASSERT_EQ(kExpectedResultCount, results.size());
678
679 ASSERT_TRUE(results.count(kPublicUnresolved));
680 EXPECT_FALSE(results[kPublicUnresolved].resolved);
681
682 ASSERT_TRUE(results.count(kRandomUnresolved));
683 EXPECT_FALSE(results[kRandomUnresolved].resolved);
684
685 ASSERT_TRUE(results.count(kPublicResolved));
686 EXPECT_TRUE(results[kPublicResolved].resolved);
687
688 ASSERT_TRUE(results.count(kRandomResolved));
689 EXPECT_TRUE(results[kRandomResolved].resolved);
690 }
691
TYPED_TEST(LowEnergyScannerTest,AllowsRandomAddressChange)692 TYPED_TEST(LowEnergyScannerTest, AllowsRandomAddressChange) {
693 EXPECT_TRUE(this->scanner()->AllowsRandomAddressChange());
694 EXPECT_TRUE(this->StartScan(false));
695
696 // Address change should not be allowed while the procedure is pending.
697 EXPECT_TRUE(this->scanner()->IsInitiating());
698 EXPECT_FALSE(this->scanner()->AllowsRandomAddressChange());
699
700 this->RunUntilIdle();
701 EXPECT_TRUE(this->scanner()->IsPassiveScanning());
702 EXPECT_FALSE(this->scanner()->AllowsRandomAddressChange());
703 }
704
TYPED_TEST(LowEnergyScannerTest,AllowsRandomAddressChangeWhileRequestingLocalAddress)705 TYPED_TEST(LowEnergyScannerTest,
706 AllowsRandomAddressChangeWhileRequestingLocalAddress) {
707 // Make the local address delegate report its result asynchronously.
708 this->fake_address_delegate()->set_async(true);
709 EXPECT_TRUE(this->StartScan(false));
710
711 // The scanner should be in the initiating state without initiating controller
712 // procedures that would prevent a local address change.
713 EXPECT_TRUE(this->scanner()->IsInitiating());
714 EXPECT_TRUE(this->scanner()->AllowsRandomAddressChange());
715
716 this->RunUntilIdle();
717 EXPECT_TRUE(this->scanner()->IsPassiveScanning());
718 EXPECT_FALSE(this->scanner()->AllowsRandomAddressChange());
719 }
720
TYPED_TEST(LowEnergyScannerTest,ScanUsingPublicAddress)721 TYPED_TEST(LowEnergyScannerTest, ScanUsingPublicAddress) {
722 this->fake_address_delegate()->set_local_address(kPublicAddress1);
723 EXPECT_TRUE(this->StartScan(false));
724 this->RunUntilIdle();
725 EXPECT_TRUE(this->scanner()->IsPassiveScanning());
726 EXPECT_EQ(pw::bluetooth::emboss::LEOwnAddressType::PUBLIC,
727 this->test_device()->le_scan_state().own_address_type);
728 }
729
TYPED_TEST(LowEnergyScannerTest,ScanUsingRandomAddress)730 TYPED_TEST(LowEnergyScannerTest, ScanUsingRandomAddress) {
731 this->fake_address_delegate()->set_local_address(kRandomAddress1);
732 EXPECT_TRUE(this->StartScan(false));
733 this->RunUntilIdle();
734 EXPECT_TRUE(this->scanner()->IsPassiveScanning());
735 EXPECT_EQ(pw::bluetooth::emboss::LEOwnAddressType::RANDOM,
736 this->test_device()->le_scan_state().own_address_type);
737 }
738
TYPED_TEST(LowEnergyScannerTest,StopScanWhileWaitingForLocalAddress)739 TYPED_TEST(LowEnergyScannerTest, StopScanWhileWaitingForLocalAddress) {
740 this->fake_address_delegate()->set_async(true);
741 EXPECT_TRUE(this->StartScan(false));
742
743 // Should be waiting for the random address.
744 EXPECT_TRUE(this->scanner()->IsInitiating());
745 EXPECT_TRUE(this->scanner()->AllowsRandomAddressChange());
746
747 EXPECT_TRUE(this->scanner()->StopScan());
748 this->RunUntilIdle();
749
750 // Should end up not scanning.
751 EXPECT_TRUE(this->scanner()->IsIdle());
752 EXPECT_FALSE(this->test_device()->le_scan_state().enabled);
753 }
754
755 } // namespace bt::hci
756