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