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/bredr_discovery_manager.h"
16
17 #include "pw_bluetooth_sapphire/internal/host/gap/peer_cache.h"
18 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
19 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
20 #include "pw_bluetooth_sapphire/internal/host/testing/inspect.h"
21 #include "pw_bluetooth_sapphire/internal/host/testing/mock_controller.h"
22 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
23 #include "pw_bluetooth_sapphire/internal/host/testing/test_packets.h"
24
25 namespace bt::gap {
26 namespace {
27
28 using namespace inspect::testing;
29
30 using TestingBase =
31 bt::testing::FakeDispatcherControllerTest<bt::testing::MockController>;
32
33 // clang-format off
34 #define COMMAND_COMPLETE_RSP(opcode) \
35 StaticByteBuffer(hci_spec::kCommandCompleteEventCode, 0x04, 0xF0, \
36 LowerBits((opcode)), UpperBits((opcode)), \
37 pw::bluetooth::emboss::StatusCode::SUCCESS)
38
39 #define COMMAND_STATUS_RSP(opcode, statuscode) \
40 StaticByteBuffer( hci_spec::kCommandStatusEventCode, 0x04, \
41 (statuscode), 0xF0, \
42 LowerBits((opcode)), UpperBits((opcode)))
43 // clang-format on
44
45 const auto kWriteInquiryActivity =
46 testing::WriteInquiryScanActivity(kInquiryScanInterval, kInquiryScanWindow);
47
48 const auto kWriteInquiryActivityRsp =
49 testing::CommandCompletePacket(hci_spec::kWriteInquiryScanActivity);
50
51 const StaticByteBuffer kWriteInquiryType(
52 LowerBits(hci_spec::kWriteInquiryScanType),
53 UpperBits(hci_spec::kWriteInquiryScanType),
54 0x01, // Param total size
55 0x01 // Interlaced Inquiry Scan
56 );
57
58 const auto kWriteInquiryTypeRsp =
59 COMMAND_COMPLETE_RSP(hci_spec::kWriteInquiryScanType);
60
61 class BrEdrDiscoveryManagerTest : public TestingBase {
62 public:
63 BrEdrDiscoveryManagerTest() = default;
64 ~BrEdrDiscoveryManagerTest() override = default;
65
SetUp()66 void SetUp() override {
67 TestingBase::SetUp();
68
69 NewDiscoveryManager(pw::bluetooth::emboss::InquiryMode::STANDARD);
70 }
71
TearDown()72 void TearDown() override {
73 discovery_manager_ = nullptr;
74 TestingBase::TearDown();
75 }
76
NewDiscoveryManager(pw::bluetooth::emboss::InquiryMode mode)77 void NewDiscoveryManager(pw::bluetooth::emboss::InquiryMode mode) {
78 // We expect to set the Inquiry Scan and the Type when we start.
79 EXPECT_CMD_PACKET_OUT(
80 test_device(), kWriteInquiryActivity, &kWriteInquiryActivityRsp);
81 EXPECT_CMD_PACKET_OUT(
82 test_device(), kWriteInquiryType, &kWriteInquiryTypeRsp);
83
84 discovery_manager_ = std::make_unique<BrEdrDiscoveryManager>(
85 dispatcher(),
86 transport()->command_channel()->AsWeakPtr(),
87 mode,
88 &peer_cache_);
89
90 RunUntilIdle();
91 }
92
DestroyDiscoveryManager()93 void DestroyDiscoveryManager() { discovery_manager_.reset(); }
94
peer_cache()95 PeerCache* peer_cache() { return &peer_cache_; }
96
97 protected:
discovery_manager() const98 BrEdrDiscoveryManager* discovery_manager() const {
99 return discovery_manager_.get();
100 }
101
102 private:
103 PeerCache peer_cache_{dispatcher()};
104 std::unique_ptr<BrEdrDiscoveryManager> discovery_manager_;
105
106 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(BrEdrDiscoveryManagerTest);
107 };
108
109 using GAP_BrEdrDiscoveryManagerTest = BrEdrDiscoveryManagerTest;
110
111 // Suffix DeathTest has GoogleTest-specific behavior
112 using BrEdrDiscoveryManagerDeathTest = BrEdrDiscoveryManagerTest;
113
114 const auto kInquiry = testing::InquiryCommandPacket();
115
116 const auto kWriteLocalNameRsp = testing::CommandCompletePacket(
117 hci_spec::kWriteLocalName, pw::bluetooth::emboss::StatusCode::SUCCESS);
118
119 const auto kWriteLocalNameRspError = testing::CommandCompletePacket(
120 hci_spec::kWriteLocalName,
121 pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE);
122
123 const auto kWriteExtendedInquiryResponseRsp =
124 testing::CommandCompletePacket(hci_spec::kWriteExtendedInquiryResponse,
125 pw::bluetooth::emboss::StatusCode::SUCCESS);
126
127 const auto kWriteExtendedInquiryResponseRspError =
128 testing::CommandCompletePacket(
129 hci_spec::kWriteExtendedInquiryResponse,
130 pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE);
131
132 const auto kInquiryRsp = testing::CommandStatusPacket(
133 hci_spec::kInquiry, pw::bluetooth::emboss::StatusCode::SUCCESS);
134
135 const auto kInquiryRspError = testing::CommandStatusPacket(
136 hci_spec::kInquiry, pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE);
137
138 const StaticByteBuffer kInquiryComplete(
139 hci_spec::kInquiryCompleteEventCode,
140 0x01, // parameter_total_size (1 bytes)
141 pw::bluetooth::emboss::StatusCode::SUCCESS);
142
143 const StaticByteBuffer kInquiryCompleteError(
144 hci_spec::kInquiryCompleteEventCode,
145 0x01, // parameter_total_size (1 bytes)
146 pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE);
147
148 #define BD_ADDR(addr1) addr1, 0x00, 0x00, 0x00, 0x00, 0x00
149
150 const DeviceAddress kDeviceAddress1(DeviceAddress::Type::kBREDR,
151 {BD_ADDR(0x01)});
152 const DeviceAddress kLeAliasAddress1(DeviceAddress::Type::kLEPublic,
153 kDeviceAddress1.value());
154 const DeviceAddress kDeviceAddress2(DeviceAddress::Type::kBREDR,
155 {BD_ADDR(0x02)});
156 const DeviceAddress kLeAliasAddress2(DeviceAddress::Type::kLEPublic,
157 kDeviceAddress2.value());
158 const DeviceAddress kDeviceAddress3(DeviceAddress::Type::kBREDR,
159 {BD_ADDR(0x03)});
160 const DeviceAddress kLeAliasAddress3(DeviceAddress::Type::kLEPublic,
161 kDeviceAddress3.value());
162
163 // clang-format off
164 const StaticByteBuffer kInquiryResult(
165 hci_spec::kInquiryResultEventCode,
166 0x0F, // parameter_total_size (15 bytes)
167 0x01, // num_responses
168 BD_ADDR(0x01), // bd_addr[0]
169 0x00, // page_scan_repetition_mode[0] (R0)
170 0x00, // unused / reserved
171 0x00, // unused / reserved
172 0x00, 0x1F, 0x00, // class_of_device[0] (unspecified)
173 0x00, 0x00 // clock_offset[0]
174 );
175
176 const StaticByteBuffer kInquiryResultIncompleteHeader(
177 hci_spec::kInquiryResultEventCode,
178 0x00 // parameter_total_size (0 bytes)
179 // truncated
180 );
181
182 const StaticByteBuffer kInquiryResultMissingResponses(
183 hci_spec::kInquiryResultEventCode,
184 0x1D, // parameter_total_size (29 bytes)
185 0x03, // num_responses (only two responses are packed)
186
187 // first response
188 BD_ADDR(0x01), // bd_addr[0]
189 0x00, // page_scan_repetition_mode[0] (R0)
190 0x00, // unused / reserved
191 0x00, // unused / reserved
192 0x00, 0x1F, 0x00, // class_of_device[0] (unspecified)
193 0x00, 0x00, // clock_offset[0]
194
195 // second response
196 BD_ADDR(0x02), // bd_addr[0]
197 0x00, // page_scan_repetition_mode[0] (R0)
198 0x00, // unused / reserved
199 0x00, // unused / reserved
200 0x00, 0x1F, 0x00, // class_of_device[0] (unspecified)
201 0x00, 0x00 // clock_offset[0]
202 );
203
204 const StaticByteBuffer kInquiryResultIncompleteResponse(
205 hci_spec::kInquiryResultEventCode,
206 0x15, // parameter_total_size (21 bytes)
207 0x02, // num_responses
208
209 // first response
210 BD_ADDR(0x01), // bd_addr[0]
211 0x00, // page_scan_repetition_mode[0] (R0)
212 0x00, // unused / reserved
213 0x00, // unused / reserved
214 0x00, 0x1F, 0x00, // class_of_device[0] (unspecified)
215 0x00, 0x00, // clock_offset[0]
216
217 // second response
218 BD_ADDR(0x02) // bd_addr[0]
219 // truncated
220 );
221
222 const StaticByteBuffer kRSSIInquiryResult(
223 hci_spec::kInquiryResultWithRSSIEventCode,
224 0x0F, // parameter_total_size (15 bytes)
225 0x01, // num_responses
226 BD_ADDR(0x02), // bd_addr[0]
227 0x00, // page_scan_repetition_mode[0] (R0)
228 0x00, // unused / reserved
229 0x00, 0x1F, 0x00, // class_of_device[0] (unspecified)
230 0x00, 0x00, // clock_offset[0]
231 0xEC // RSSI (-20dBm)
232 );
233
234 #define REMOTE_NAME_REQUEST(addr1) StaticByteBuffer( \
235 LowerBits(hci_spec::kRemoteNameRequest), UpperBits(hci_spec::kRemoteNameRequest), \
236 0x0a, /* parameter_total_size (10 bytes) */ \
237 BD_ADDR(addr1), /* BD_ADDR */ \
238 0x00, 0x00, 0x00, 0x80 /* page_scan_repetition_mode, 0, clock_offset */ \
239 );
240
241 const auto kRemoteNameRequest1 = REMOTE_NAME_REQUEST(0x01)
242 const auto kRemoteNameRequest2 = REMOTE_NAME_REQUEST(0x02)
243
244 #undef REMOTE_NAME_REQUEST
245
246 const auto kRemoteNameRequestRsp =
247 COMMAND_STATUS_RSP(hci_spec::kRemoteNameRequest, pw::bluetooth::emboss::StatusCode::SUCCESS);
248
249 #undef COMMAND_STATUS_RSP
250
251 const auto kRemoteNameRequestComplete1 = testing::RemoteNameRequestCompletePacket(
252 kDeviceAddress1, {'F', 'u', 'c', 'h', 's', 'i', 'a', '\xF0', '\x9F',
253 '\x92', '\x96', '\x00', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19',
254 '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', '\x20'}
255 // remote name (Fuchsia)
256 // Everything after the 0x00 should be ignored.
257 );
258 const auto kRemoteNameRequestComplete2 =
259 testing::RemoteNameRequestCompletePacket(kDeviceAddress2, "Sapphire");
260
261 const StaticByteBuffer kExtendedInquiryResult(
262 hci_spec::kExtendedInquiryResultEventCode,
263 0xFF, // parameter_total_size (255 bytes)
264 0x01, // num_responses
265 BD_ADDR(0x03), // bd_addr
266 0x00, // page_scan_repetition_mode (R0)
267 0x00, // unused / reserved
268 0x00, 0x1F, 0x00, // class_of_device (unspecified)
269 0x00, 0x00, // clock_offset
270 0xEC, // RSSI (-20dBm)
271 // Extended Inquiry Response (240 bytes total)
272 // Complete Local Name (12 bytes): Fuchsia
273 0x0C, 0x09, 'F', 'u', 'c', 'h', 's', 'i', 'a', 0xF0, 0x9F, 0x92, 0x96,
274 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
275 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
276 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
292 );
293
294 #undef BD_ADDR
295
296 const StaticByteBuffer kSetExtendedMode(
297 LowerBits(hci_spec::kWriteInquiryMode), UpperBits(hci_spec::kWriteInquiryMode),
298 0x01, // parameter_total_size
299 0x02 // Extended Inquiry Result or Inquiry Result with RSSI
300 );
301
302 const auto kSetExtendedModeRsp = COMMAND_COMPLETE_RSP(hci_spec::kWriteInquiryMode);
303
304 const StaticByteBuffer kWriteLocalName(
305 LowerBits(hci_spec::kWriteLocalName), UpperBits(hci_spec::kWriteLocalName),
306 0xF8, // parameter_total_size (248 bytes)
307 // Complete Local Name ()
308 'A', 'B', 'C', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 0x00
328 );
329
330 const StaticByteBuffer kWriteExtendedInquiryResponse(
331 LowerBits(hci_spec::kWriteExtendedInquiryResponse),
332 UpperBits(hci_spec::kWriteExtendedInquiryResponse),
333 0xF1, // parameter_total_size (241 bytes)
334 0x00, // fec_required
335 0x04, // name_length + 1
336 0x09, // DataType::kCompleteLocalName,
337 // Complete Local Name (3 bytes + 1 byte null terminator + 234 bytes of zero padding)
338 'A', 'B', 'C', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
348 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
349 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
357 );
358
359 const auto kReadScanEnable = testing::ReadScanEnable();
360 const auto kReadScanEnableRspNone = testing::ReadScanEnableResponse(0x00);
361 const auto kReadScanEnableRspInquiry = testing::ReadScanEnableResponse(0x01);
362 const auto kReadScanEnableRspPage = testing::ReadScanEnableResponse(0x02);
363 const auto kReadScanEnableRspBoth = testing::ReadScanEnableResponse(0x03);
364
365 const auto kWriteScanEnableNone = testing::WriteScanEnable(0x00);
366 const auto kWriteScanEnableInq = testing::WriteScanEnable(0x01);
367 const auto kWriteScanEnablePage = testing::WriteScanEnable(0x02);
368 const auto kWriteScanEnableBoth = testing::WriteScanEnable(0x03);
369 const auto kWriteScanEnableRsp = testing::CommandCompletePacket(hci_spec::kWriteScanEnable);
370
371 #undef COMMAND_COMPLETE_RSP
372 // clang-format on
373
374 // Test: malformed inquiry result is fatal
TEST_F(BrEdrDiscoveryManagerDeathTest,MalformedInquiryResultFromControllerIsFatal)375 TEST_F(BrEdrDiscoveryManagerDeathTest,
376 MalformedInquiryResultFromControllerIsFatal) {
377 EXPECT_CMD_PACKET_OUT(test_device(), hci_spec::kInquiry, &kInquiryRsp);
378
379 std::unique_ptr<BrEdrDiscoverySession> session;
380
381 discovery_manager()->RequestDiscovery(
382 [&session](auto status, auto cb_session) {
383 EXPECT_EQ(fit::ok(), status);
384 session = std::move(cb_session);
385 });
386
387 RunUntilIdle();
388
389 for (auto event : {kInquiryResultIncompleteHeader.view(),
390 kInquiryResultMissingResponses.view(),
391 kInquiryResultIncompleteResponse.view()}) {
392 EXPECT_DEATH_IF_SUPPORTED(
393 (test_device()->SendCommandChannelPacket(event), RunUntilIdle()), ".*");
394 }
395 }
396
397 // Test: discovering() answers correctly
398
399 // Test: requesting discovery should start inquiry
400 // Test: Inquiry Results that come in when there is discovery get reported up
401 // correctly to the sessions
402 // Test: Peers discovered are reported to the cache
403 // Test: RemoteNameRequest is processed correctly
404 // Test: Inquiry Results that come in when there's no discovery happening get
405 // discarded.
TEST_F(BrEdrDiscoveryManagerTest,RequestDiscoveryAndDrop)406 TEST_F(BrEdrDiscoveryManagerTest, RequestDiscoveryAndDrop) {
407 EXPECT_CMD_PACKET_OUT(
408 test_device(), hci_spec::kInquiry, &kInquiryRsp, &kInquiryResult);
409 EXPECT_CMD_PACKET_OUT(test_device(),
410 kRemoteNameRequest1,
411 &kRemoteNameRequestRsp,
412 &kRemoteNameRequestComplete1);
413
414 std::unique_ptr<BrEdrDiscoverySession> session;
415 size_t peers_found = 0u;
416
417 discovery_manager()->RequestDiscovery(
418 [&session, &peers_found](auto status, auto cb_session) {
419 EXPECT_EQ(fit::ok(), status);
420 cb_session->set_result_callback(
421 [&peers_found](const auto&) { peers_found++; });
422 session = std::move(cb_session);
423 });
424
425 EXPECT_FALSE(discovery_manager()->discovering());
426
427 RunUntilIdle();
428
429 EXPECT_EQ(1u, peers_found);
430 EXPECT_TRUE(discovery_manager()->discovering());
431
432 EXPECT_CMD_PACKET_OUT(
433 test_device(), hci_spec::kInquiry, &kInquiryRsp, &kInquiryResult);
434
435 test_device()->SendCommandChannelPacket(kInquiryComplete);
436
437 RunUntilIdle();
438
439 // Confirm that post-inquiry peer name request is processed correctly.
440 Peer* peer = peer_cache()->FindByAddress(kDeviceAddress1);
441 ASSERT_TRUE(peer);
442 EXPECT_EQ("Fuchsia", *peer->name());
443 EXPECT_EQ(Peer::NameSource::kNameDiscoveryProcedure, *peer->name_source());
444
445 EXPECT_EQ(2u, peers_found);
446
447 // TODO(fxbug.dev/42145646): test InquiryCancel when it is implemented
448
449 session = nullptr;
450 test_device()->SendCommandChannelPacket(kInquiryResult);
451
452 RunUntilIdle();
453
454 EXPECT_EQ(2u, peers_found);
455 EXPECT_FALSE(discovery_manager()->discovering());
456
457 test_device()->SendCommandChannelPacket(kInquiryComplete);
458 RunUntilIdle();
459 }
460
461 // Test: requesting a second discovery should start a session without sending
462 // any more HCI commands.
463 // Test: dropping the first discovery shouldn't stop inquiry
464 // Test: starting two sessions at once should only start inquiry once
TEST_F(BrEdrDiscoveryManagerTest,MultipleRequests)465 TEST_F(BrEdrDiscoveryManagerTest, MultipleRequests) {
466 EXPECT_CMD_PACKET_OUT(
467 test_device(), hci_spec::kInquiry, &kInquiryRsp, &kInquiryResult);
468 EXPECT_CMD_PACKET_OUT(test_device(),
469 kRemoteNameRequest1,
470 &kRemoteNameRequestRsp,
471 &kRemoteNameRequestComplete1);
472
473 std::unique_ptr<BrEdrDiscoverySession> session1;
474 size_t peers_found1 = 0u;
475
476 discovery_manager()->RequestDiscovery(
477 [&session1, &peers_found1](auto status, auto cb_session) {
478 EXPECT_EQ(fit::ok(), status);
479 cb_session->set_result_callback(
480 [&peers_found1](const auto&) { peers_found1++; });
481 session1 = std::move(cb_session);
482 });
483
484 EXPECT_FALSE(discovery_manager()->discovering());
485
486 RunUntilIdle();
487
488 EXPECT_TRUE(session1);
489 EXPECT_EQ(1u, peers_found1);
490 EXPECT_TRUE(discovery_manager()->discovering());
491
492 std::unique_ptr<BrEdrDiscoverySession> session2;
493 size_t peers_found2 = 0u;
494
495 discovery_manager()->RequestDiscovery(
496 [&session2, &peers_found2](auto status, auto cb_session) {
497 EXPECT_EQ(fit::ok(), status);
498 cb_session->set_result_callback(
499 [&peers_found2](const auto&) { peers_found2++; });
500 session2 = std::move(cb_session);
501 });
502
503 RunUntilIdle();
504
505 EXPECT_TRUE(session2);
506 EXPECT_EQ(1u, peers_found1);
507 EXPECT_EQ(0u, peers_found2);
508 EXPECT_TRUE(discovery_manager()->discovering());
509
510 test_device()->SendCommandChannelPacket(kInquiryResult);
511
512 RunUntilIdle();
513
514 EXPECT_EQ(2u, peers_found1);
515 EXPECT_EQ(1u, peers_found2);
516
517 session1 = nullptr;
518
519 RunUntilIdle();
520
521 test_device()->SendCommandChannelPacket(kInquiryResult);
522
523 RunUntilIdle();
524
525 EXPECT_EQ(2u, peers_found1);
526 EXPECT_EQ(2u, peers_found2);
527
528 // TODO(fxbug.dev/42145646): test InquiryCancel when it is implemented
529
530 session2 = nullptr;
531
532 test_device()->SendCommandChannelPacket(kInquiryResult);
533
534 RunUntilIdle();
535
536 EXPECT_EQ(2u, peers_found1);
537 EXPECT_EQ(2u, peers_found2);
538
539 EXPECT_FALSE(discovery_manager()->discovering());
540
541 test_device()->SendCommandChannelPacket(kInquiryComplete);
542
543 RunUntilIdle();
544 }
545
546 // Test: starting a session "while" the other one is stopping a session should
547 // still restart the Inquiry.
548 // Test: starting a session "while" the other one is stopping should return
549 // without needing an InquiryComplete first.
550 // Test: we should only request a peer's name if it's the first time we
551 // encounter it.
TEST_F(BrEdrDiscoveryManagerTest,RequestDiscoveryWhileStop)552 TEST_F(BrEdrDiscoveryManagerTest, RequestDiscoveryWhileStop) {
553 EXPECT_CMD_PACKET_OUT(test_device(), kInquiry, &kInquiryRsp, &kInquiryResult);
554 EXPECT_CMD_PACKET_OUT(test_device(),
555 kRemoteNameRequest1,
556 &kRemoteNameRequestRsp,
557 &kRemoteNameRequestComplete1);
558
559 std::unique_ptr<BrEdrDiscoverySession> session1;
560 size_t peers_found1 = 0u;
561
562 discovery_manager()->RequestDiscovery(
563 [&session1, &peers_found1](auto status, auto cb_session) {
564 EXPECT_EQ(fit::ok(), status);
565 cb_session->set_result_callback(
566 [&peers_found1](const auto&) { peers_found1++; });
567 session1 = std::move(cb_session);
568 });
569
570 EXPECT_FALSE(discovery_manager()->discovering());
571
572 RunUntilIdle();
573
574 EXPECT_TRUE(session1);
575 EXPECT_EQ(1u, peers_found1);
576 EXPECT_TRUE(discovery_manager()->discovering());
577
578 // Drop the active session.
579 session1 = nullptr;
580 RunUntilIdle();
581
582 std::unique_ptr<BrEdrDiscoverySession> session2;
583 size_t peers_found2 = 0u;
584 discovery_manager()->RequestDiscovery(
585 [&session2, &peers_found2](auto status, auto cb_session) {
586 EXPECT_EQ(fit::ok(), status);
587 cb_session->set_result_callback(
588 [&peers_found2](const auto&) { peers_found2++; });
589 session2 = std::move(cb_session);
590 });
591
592 // The new session should be started at this point, and inquiry results
593 // returned.
594 EXPECT_TRUE(session2);
595 test_device()->SendCommandChannelPacket(kInquiryResult);
596
597 RunUntilIdle();
598
599 EXPECT_EQ(1u, peers_found2);
600
601 // Inquiry should be restarted when the Complete comes in because an active
602 // session2 still exists.
603 // TODO(fxbug.dev/42145646): test InquiryCancel when it is implemented
604 EXPECT_CMD_PACKET_OUT(test_device(), kInquiry, &kInquiryRsp, &kInquiryResult);
605 test_device()->SendCommandChannelPacket(kInquiryComplete);
606
607 RunUntilIdle();
608
609 EXPECT_EQ(1u, peers_found1);
610 EXPECT_EQ(2u, peers_found2);
611 EXPECT_TRUE(discovery_manager()->discovering());
612
613 test_device()->SendCommandChannelPacket(kInquiryResult);
614
615 RunUntilIdle();
616
617 EXPECT_EQ(1u, peers_found1);
618 EXPECT_EQ(3u, peers_found2);
619
620 // TODO(fxbug.dev/42145646): test InquiryCancel when it is implemented
621 session2 = nullptr;
622
623 // After the session is dropped, even if another result comes in, no results
624 // are sent to the callback.
625 test_device()->SendCommandChannelPacket(kInquiryResult);
626
627 RunUntilIdle();
628
629 EXPECT_EQ(1u, peers_found1);
630 EXPECT_EQ(3u, peers_found2);
631 }
632
633 // Test: When Inquiry Fails to start, we report this back to the requester.
TEST_F(BrEdrDiscoveryManagerTest,RequestDiscoveryError)634 TEST_F(BrEdrDiscoveryManagerTest, RequestDiscoveryError) {
635 EXPECT_CMD_PACKET_OUT(
636 test_device(), kInquiry, &kInquiryRspError, &kInquiryResult);
637 EXPECT_CMD_PACKET_OUT(test_device(),
638 kRemoteNameRequest1,
639 &kRemoteNameRequestRsp,
640 &kRemoteNameRequestComplete1);
641
642 std::unique_ptr<BrEdrDiscoverySession> session;
643
644 discovery_manager()->RequestDiscovery([](auto status, auto cb_session) {
645 EXPECT_TRUE(status.is_error());
646 EXPECT_FALSE(cb_session);
647 EXPECT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE),
648 status);
649 });
650
651 EXPECT_FALSE(discovery_manager()->discovering());
652
653 RunUntilIdle();
654
655 EXPECT_FALSE(discovery_manager()->discovering());
656 }
657
658 // Test: When inquiry complete indicates failure, we signal to the current
659 // sessions.
TEST_F(BrEdrDiscoveryManagerTest,ContinuingDiscoveryError)660 TEST_F(BrEdrDiscoveryManagerTest, ContinuingDiscoveryError) {
661 EXPECT_CMD_PACKET_OUT(test_device(), kInquiry, &kInquiryRsp, &kInquiryResult);
662 EXPECT_CMD_PACKET_OUT(test_device(),
663 kRemoteNameRequest1,
664 &kRemoteNameRequestRsp,
665 &kRemoteNameRequestComplete1);
666
667 std::unique_ptr<BrEdrDiscoverySession> session;
668 size_t peers_found = 0u;
669 bool error_callback = false;
670
671 discovery_manager()->RequestDiscovery(
672 [&session, &peers_found, &error_callback](auto status, auto cb_session) {
673 EXPECT_EQ(fit::ok(), status);
674 cb_session->set_result_callback(
675 [&peers_found](const auto&) { peers_found++; });
676 cb_session->set_error_callback(
677 [&error_callback]() { error_callback = true; });
678 session = std::move(cb_session);
679 });
680
681 EXPECT_FALSE(discovery_manager()->discovering());
682
683 RunUntilIdle();
684
685 EXPECT_EQ(1u, peers_found);
686 EXPECT_TRUE(discovery_manager()->discovering());
687
688 test_device()->SendCommandChannelPacket(kInquiryCompleteError);
689
690 RunUntilIdle();
691
692 EXPECT_TRUE(error_callback);
693 EXPECT_FALSE(discovery_manager()->discovering());
694
695 session = nullptr;
696
697 RunUntilIdle();
698 }
699
700 // clang-format off
701 const StaticByteBuffer kWriteLocalNameMaxLen(
702 LowerBits(hci_spec::kWriteLocalName), UpperBits(hci_spec::kWriteLocalName),
703 0xF8, // parameter_total_size (248 bytes)
704 // Complete Local Name (exactly 248 bytes)
705 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
706 'T', 'U', 'V', 'W', 'X', 'Y',
707 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
708 'T', 'U', 'V', 'W', 'X', 'Y',
709 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
710 'T', 'U', 'V', 'W', 'X', 'Y',
711 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
712 'T', 'U', 'V', 'W', 'X', 'Y',
713 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
714 'T', 'U', 'V', 'W', 'X', 'Y',
715 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
716 'T', 'U', 'V', 'W', 'X', 'Y',
717 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
718 'T', 'U', 'V', 'W', 'X', 'Y',
719 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
720 'T', 'U', 'V', 'W', 'X', 'Y',
721 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
722 'T', 'U', 'V', 'W', 'X', 'Y',
723 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
724 'T', 'U', 'V', 'W'
725 );
726
727 const StaticByteBuffer kWriteExtInquiryResponseMaxLen(
728 LowerBits(hci_spec::kWriteExtendedInquiryResponse),
729 UpperBits(hci_spec::kWriteExtendedInquiryResponse),
730 0xF1, // parameter_total_size (241 bytes)
731 0x00, // fec_required
732 0xEF, // 239 bytes (1 + 238 bytes)
733 0x08, // DataType::kShortenedLocalName,
734 // Shortened Local Name (238 bytes, truncated from above)
735 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
736 'T', 'U', 'V', 'W', 'X', 'Y',
737 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
738 'T', 'U', 'V', 'W', 'X', 'Y',
739 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
740 'T', 'U', 'V', 'W', 'X', 'Y',
741 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
742 'T', 'U', 'V', 'W', 'X', 'Y',
743 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
744 'T', 'U', 'V', 'W', 'X', 'Y',
745 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
746 'T', 'U', 'V', 'W', 'X', 'Y',
747 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
748 'T', 'U', 'V', 'W', 'X', 'Y',
749 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
750 'T', 'U', 'V', 'W', 'X', 'Y',
751 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
752 'T', 'U', 'V', 'W', 'X', 'Y',
753 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M'
754 );
755 // clang-format on
756
757 // Test: UpdateLocalName successfully sends hci command, and further calls
758 // UpdateEIRResponseData (private). Ensures the name is updated at the very end.
TEST_F(BrEdrDiscoveryManagerTest,UpdateLocalNameShortenedSuccess)759 TEST_F(BrEdrDiscoveryManagerTest, UpdateLocalNameShortenedSuccess) {
760 EXPECT_CMD_PACKET_OUT(test_device(), kWriteLocalNameMaxLen, );
761
762 // Set the status to be an arbitrary invalid status.
763 hci::Result<> result =
764 ToResult(pw::bluetooth::emboss::StatusCode::PAIRING_NOT_ALLOWED);
765 size_t callback_count = 0u;
766 auto name_cb = [&result, &callback_count](const auto& status) {
767 EXPECT_EQ(fit::ok(), status);
768 callback_count++;
769 result = status;
770 };
771 std::string kNewName = "";
772 while (kNewName.length() < 225) {
773 kNewName.append("ABCDEFGHIJKLMNOPQRSTUVWXY");
774 }
775 kNewName.append("ABCDEFGHIJKLMNOPQRSTUVW");
776 discovery_manager()->UpdateLocalName(kNewName, name_cb);
777
778 RunUntilIdle();
779
780 // Local name should not be set, callback shouldn't be called yet.
781 EXPECT_NE(kNewName, discovery_manager()->local_name());
782 EXPECT_EQ(0u, callback_count);
783
784 test_device()->SendCommandChannelPacket(kWriteLocalNameRsp);
785 EXPECT_CMD_PACKET_OUT(test_device(), kWriteExtInquiryResponseMaxLen, );
786
787 RunUntilIdle();
788
789 // Still waiting on EIR response.
790 // Local name should not be set, callback shouldn't be called yet.
791 EXPECT_NE(kNewName, discovery_manager()->local_name());
792 EXPECT_EQ(0u, callback_count);
793
794 test_device()->SendCommandChannelPacket(kWriteExtendedInquiryResponseRsp);
795
796 RunUntilIdle();
797
798 EXPECT_EQ(kNewName, discovery_manager()->local_name());
799 EXPECT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::SUCCESS), result);
800 EXPECT_EQ(1u, callback_count);
801 }
802
803 // Test: UpdateLocalName successfully sends hci command, and further calls
804 // UpdateEIRResponseData (private). Ensures the name is updated at the very end.
TEST_F(BrEdrDiscoveryManagerTest,UpdateLocalNameSuccess)805 TEST_F(BrEdrDiscoveryManagerTest, UpdateLocalNameSuccess) {
806 EXPECT_CMD_PACKET_OUT(test_device(), kWriteLocalName, );
807
808 // Set the status to be an arbitrary invalid status.
809 hci::Result<> result =
810 ToResult(pw::bluetooth::emboss::StatusCode::PAIRING_NOT_ALLOWED);
811 size_t callback_count = 0u;
812 auto name_cb = [&result, &callback_count](const auto& status) {
813 EXPECT_EQ(fit::ok(), status);
814 callback_count++;
815 result = status;
816 };
817 const std::string kNewName = "ABC";
818 discovery_manager()->UpdateLocalName(kNewName, name_cb);
819
820 RunUntilIdle();
821
822 // Local name should not be set, callback shouldn't be called yet.
823 EXPECT_NE(kNewName, discovery_manager()->local_name());
824 EXPECT_EQ(0u, callback_count);
825
826 test_device()->SendCommandChannelPacket(kWriteLocalNameRsp);
827 EXPECT_CMD_PACKET_OUT(test_device(), kWriteExtendedInquiryResponse, );
828
829 RunUntilIdle();
830
831 // Still waiting on EIR response.
832 // Local name should not be set, callback shouldn't be called yet.
833 EXPECT_NE(kNewName, discovery_manager()->local_name());
834 EXPECT_EQ(0u, callback_count);
835
836 test_device()->SendCommandChannelPacket(kWriteExtendedInquiryResponseRsp);
837
838 RunUntilIdle();
839
840 EXPECT_EQ(kNewName, discovery_manager()->local_name());
841 EXPECT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::SUCCESS), result);
842 EXPECT_EQ(1u, callback_count);
843 }
844
845 // Test: UpdateLocalName passes back error code through the callback and
846 // |local_name_| does not get updated.
TEST_F(BrEdrDiscoveryManagerTest,UpdateLocalNameError)847 TEST_F(BrEdrDiscoveryManagerTest, UpdateLocalNameError) {
848 EXPECT_CMD_PACKET_OUT(test_device(), kWriteLocalName, );
849
850 // Set the status to be an arbitrary invalid status.
851 hci::Result<> result =
852 ToResult(pw::bluetooth::emboss::StatusCode::UNSUPPORTED_REMOTE_FEATURE);
853 size_t callback_count = 0u;
854 auto name_cb = [&result, &callback_count](const auto& status) {
855 EXPECT_TRUE(status.is_error());
856 callback_count++;
857 result = status;
858 };
859 const std::string kNewName = "ABC";
860 discovery_manager()->UpdateLocalName(kNewName, name_cb);
861
862 RunUntilIdle();
863
864 // Local name should not be set, callback shouldn't be called yet.
865 EXPECT_NE(kNewName, discovery_manager()->local_name());
866 EXPECT_EQ(0u, callback_count);
867
868 // Send a response error.
869 test_device()->SendCommandChannelPacket(kWriteLocalNameRspError);
870
871 RunUntilIdle();
872
873 // |local_name_| should not be updated, return status should be error.
874 EXPECT_NE(kNewName, discovery_manager()->local_name());
875 EXPECT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE),
876 result);
877 EXPECT_EQ(1u, callback_count);
878 }
879
880 // Test: UpdateLocalName should succeed, but UpdateEIRResponseData should fail.
881 // Consequently, the |local_name_| should not be updated, and the callback
882 // should return the error.
TEST_F(BrEdrDiscoveryManagerTest,UpdateEIRResponseDataError)883 TEST_F(BrEdrDiscoveryManagerTest, UpdateEIRResponseDataError) {
884 EXPECT_CMD_PACKET_OUT(test_device(), kWriteLocalName, );
885
886 // Set the status to be an arbitrary invalid status.
887 hci::Result<> result =
888 ToResult(pw::bluetooth::emboss::StatusCode::UNSUPPORTED_REMOTE_FEATURE);
889 size_t callback_count = 0u;
890 auto name_cb = [&result, &callback_count](const auto& status) {
891 EXPECT_TRUE(status.is_error());
892 callback_count++;
893 result = status;
894 };
895 const std::string kNewName = "ABC";
896 discovery_manager()->UpdateLocalName(kNewName, name_cb);
897
898 RunUntilIdle();
899
900 // Local name should not be set, callback shouldn't be called yet.
901 EXPECT_NE(kNewName, discovery_manager()->local_name());
902 EXPECT_EQ(0u, callback_count);
903
904 // kWriteLocalName should succeed.
905 test_device()->SendCommandChannelPacket(kWriteLocalNameRsp);
906 EXPECT_CMD_PACKET_OUT(test_device(), kWriteExtendedInquiryResponse, );
907
908 RunUntilIdle();
909
910 // Still waiting on EIR response.
911 // Local name should not be set, callback shouldn't be called yet.
912 EXPECT_NE(kNewName, discovery_manager()->local_name());
913 EXPECT_EQ(0u, callback_count);
914
915 // kWriteExtendedInquiryResponse should fail.
916 test_device()->SendCommandChannelPacket(
917 kWriteExtendedInquiryResponseRspError);
918
919 RunUntilIdle();
920
921 // |local_name_| should not be updated, return status should be error.
922 EXPECT_NE(kNewName, discovery_manager()->local_name());
923 EXPECT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE),
924 result);
925 EXPECT_EQ(1u, callback_count);
926 }
927
928 // Test: requesting discoverable works
929 // Test: requesting discoverable while discoverable is pending doesn't send
930 // any more HCI commands
TEST_F(BrEdrDiscoveryManagerTest,DiscoverableSet)931 TEST_F(BrEdrDiscoveryManagerTest, DiscoverableSet) {
932 EXPECT_CMD_PACKET_OUT(test_device(), kReadScanEnable, );
933
934 std::vector<std::unique_ptr<BrEdrDiscoverableSession>> sessions;
935 auto session_cb = [&sessions](auto status, auto cb_session) {
936 EXPECT_EQ(fit::ok(), status);
937 sessions.emplace_back(std::move(cb_session));
938 };
939
940 discovery_manager()->RequestDiscoverable(session_cb);
941
942 RunUntilIdle();
943
944 EXPECT_EQ(0u, sessions.size());
945 EXPECT_FALSE(discovery_manager()->discoverable());
946
947 EXPECT_CMD_PACKET_OUT(test_device(), kWriteScanEnableInq, );
948
949 test_device()->SendCommandChannelPacket(kReadScanEnableRspNone);
950
951 RunUntilIdle();
952
953 // Request another session while the first is pending.
954 discovery_manager()->RequestDiscoverable(session_cb);
955
956 test_device()->SendCommandChannelPacket(kWriteScanEnableRsp);
957
958 RunUntilIdle();
959
960 EXPECT_EQ(2u, sessions.size());
961 EXPECT_TRUE(discovery_manager()->discoverable());
962
963 discovery_manager()->RequestDiscoverable(session_cb);
964
965 EXPECT_EQ(3u, sessions.size());
966 EXPECT_TRUE(discovery_manager()->discoverable());
967
968 EXPECT_CMD_PACKET_OUT(
969 test_device(), kReadScanEnable, &kReadScanEnableRspInquiry);
970 EXPECT_CMD_PACKET_OUT(
971 test_device(), kWriteScanEnableNone, &kWriteScanEnableRsp);
972
973 sessions.clear();
974
975 RunUntilIdle();
976
977 EXPECT_FALSE(discovery_manager()->discoverable());
978 }
979
980 // Test: requesting discoverable while discovery is disabling leaves
981 // the discoverable enabled and reports success
982 // Test: enable/disable while page scan is enabled works.
TEST_F(BrEdrDiscoveryManagerTest,DiscoverableRequestWhileStopping)983 TEST_F(BrEdrDiscoveryManagerTest, DiscoverableRequestWhileStopping) {
984 EXPECT_CMD_PACKET_OUT(
985 test_device(), kReadScanEnable, &kReadScanEnableRspPage);
986 EXPECT_CMD_PACKET_OUT(
987 test_device(), kWriteScanEnableBoth, &kWriteScanEnableRsp);
988
989 std::vector<std::unique_ptr<BrEdrDiscoverableSession>> sessions;
990 auto session_cb = [&sessions](auto status, auto cb_session) {
991 EXPECT_EQ(fit::ok(), status);
992 sessions.emplace_back(std::move(cb_session));
993 };
994
995 discovery_manager()->RequestDiscoverable(session_cb);
996
997 RunUntilIdle();
998
999 EXPECT_EQ(1u, sessions.size());
1000 EXPECT_TRUE(discovery_manager()->discoverable());
1001
1002 EXPECT_CMD_PACKET_OUT(test_device(), kReadScanEnable, );
1003
1004 sessions.clear();
1005
1006 RunUntilIdle();
1007
1008 // Request a new discovery before the procedure finishes.
1009 // This will queue another ReadScanEnable just in case the disable write is
1010 // in progress.
1011 EXPECT_CMD_PACKET_OUT(test_device(), kReadScanEnable, );
1012 discovery_manager()->RequestDiscoverable(session_cb);
1013
1014 test_device()->SendCommandChannelPacket(kReadScanEnableRspBoth);
1015
1016 // This shouldn't send any WriteScanEnable because we're already in the right
1017 // mode (MockController will assert if we do as it's not expecting)
1018 RunUntilIdle();
1019
1020 EXPECT_EQ(1u, sessions.size());
1021 EXPECT_TRUE(discovery_manager()->discoverable());
1022
1023 // If somehow the scan got turned off, we will still turn it back on.
1024 EXPECT_CMD_PACKET_OUT(
1025 test_device(), kWriteScanEnableBoth, &kWriteScanEnableRsp);
1026 test_device()->SendCommandChannelPacket(kReadScanEnableRspPage);
1027
1028 RunUntilIdle();
1029
1030 EXPECT_EQ(1u, sessions.size());
1031 EXPECT_TRUE(discovery_manager()->discoverable());
1032
1033 EXPECT_CMD_PACKET_OUT(
1034 test_device(), kReadScanEnable, &kReadScanEnableRspBoth);
1035 EXPECT_CMD_PACKET_OUT(
1036 test_device(), kWriteScanEnablePage, &kWriteScanEnableRsp);
1037
1038 sessions.clear();
1039
1040 RunUntilIdle();
1041
1042 EXPECT_FALSE(discovery_manager()->discoverable());
1043 }
1044
1045 // Test: non-standard inquiry modes mean before the first discovery, the
1046 // inquiry mode is set.
1047 // Test: extended inquiry is stored in the remote peer
TEST_F(BrEdrDiscoveryManagerTest,ExtendedInquiry)1048 TEST_F(BrEdrDiscoveryManagerTest, ExtendedInquiry) {
1049 NewDiscoveryManager(pw::bluetooth::emboss::InquiryMode::EXTENDED);
1050
1051 EXPECT_CMD_PACKET_OUT(test_device(), kSetExtendedMode, &kSetExtendedModeRsp);
1052 EXPECT_CMD_PACKET_OUT(test_device(),
1053 kInquiry,
1054 &kInquiryRsp,
1055 &kExtendedInquiryResult,
1056 &kRSSIInquiryResult);
1057 EXPECT_CMD_PACKET_OUT(test_device(),
1058 kRemoteNameRequest2,
1059 &kRemoteNameRequestRsp,
1060 &kRemoteNameRequestComplete2);
1061
1062 std::unique_ptr<BrEdrDiscoverySession> session1;
1063 size_t peers_found1 = 0u;
1064
1065 discovery_manager()->RequestDiscovery(
1066 [&session1, &peers_found1](auto status, auto cb_session) {
1067 EXPECT_EQ(fit::ok(), status);
1068 cb_session->set_result_callback(
1069 [&peers_found1](const auto&) { peers_found1++; });
1070 session1 = std::move(cb_session);
1071 });
1072
1073 EXPECT_FALSE(discovery_manager()->discovering());
1074
1075 RunUntilIdle();
1076
1077 EXPECT_TRUE(session1);
1078 EXPECT_EQ(2u, peers_found1);
1079 EXPECT_TRUE(discovery_manager()->discovering());
1080 session1 = nullptr;
1081
1082 Peer* peer1 = peer_cache()->FindByAddress(kDeviceAddress2);
1083 ASSERT_TRUE(peer1);
1084 EXPECT_EQ(-20, peer1->rssi());
1085
1086 Peer* peer2 = peer_cache()->FindByAddress(kDeviceAddress3);
1087 ASSERT_TRUE(peer2);
1088 ASSERT_TRUE(peer2->name());
1089 EXPECT_EQ("Fuchsia", *peer2->name());
1090 EXPECT_EQ(Peer::NameSource::kInquiryResultComplete, *peer2->name_source());
1091
1092 test_device()->SendCommandChannelPacket(kInquiryComplete);
1093
1094 RunUntilIdle();
1095
1096 EXPECT_FALSE(discovery_manager()->discovering());
1097 }
1098
1099 // Verify that receiving a inquiry response for a known LE non-connectable peer
1100 // results in the peer being changed to DualMode and connectable.
TEST_F(BrEdrDiscoveryManagerTest,InquiryResultUpgradesKnownLowEnergyPeer)1101 TEST_F(BrEdrDiscoveryManagerTest, InquiryResultUpgradesKnownLowEnergyPeer) {
1102 Peer* peer = peer_cache()->NewPeer(kLeAliasAddress1, /*connectable=*/false);
1103 ASSERT_TRUE(peer);
1104 ASSERT_FALSE(peer->connectable());
1105 ASSERT_EQ(TechnologyType::kLowEnergy, peer->technology());
1106
1107 EXPECT_CMD_PACKET_OUT(test_device(), kInquiry, &kInquiryRsp, &kInquiryResult);
1108 EXPECT_CMD_PACKET_OUT(test_device(),
1109 kRemoteNameRequest1,
1110 &kRemoteNameRequestRsp,
1111 &kRemoteNameRequestComplete1);
1112
1113 std::unique_ptr<BrEdrDiscoverySession> session;
1114 size_t peers_found = 0u;
1115
1116 discovery_manager()->RequestDiscovery([&session, &peers_found](
1117 auto status, auto cb_session) {
1118 EXPECT_EQ(fit::ok(), status);
1119 cb_session->set_result_callback([&peers_found](auto&) { peers_found++; });
1120 session = std::move(cb_session);
1121 });
1122 RunUntilIdle();
1123 session = nullptr;
1124
1125 EXPECT_EQ(1u, peers_found);
1126 ASSERT_EQ(peer, peer_cache()->FindByAddress(kDeviceAddress1));
1127 EXPECT_EQ(TechnologyType::kDualMode, peer->technology());
1128 EXPECT_TRUE(peer->connectable());
1129
1130 test_device()->SendCommandChannelPacket(kInquiryComplete);
1131
1132 RunUntilIdle();
1133 }
1134
1135 // Verify that receiving an extended inquiry response for a known LE
1136 // non-connectable peer results in the peer being changed to DualMode and
1137 // connectable.
TEST_F(BrEdrDiscoveryManagerTest,ExtendedInquiryResultUpgradesKnownLowEnergyPeer)1138 TEST_F(BrEdrDiscoveryManagerTest,
1139 ExtendedInquiryResultUpgradesKnownLowEnergyPeer) {
1140 Peer* peer = peer_cache()->NewPeer(kLeAliasAddress3, /*connectable=*/false);
1141 ASSERT_TRUE(peer);
1142 ASSERT_FALSE(peer->connectable());
1143 ASSERT_EQ(TechnologyType::kLowEnergy, peer->technology());
1144
1145 NewDiscoveryManager(pw::bluetooth::emboss::InquiryMode::EXTENDED);
1146
1147 EXPECT_CMD_PACKET_OUT(test_device(), kSetExtendedMode, &kSetExtendedModeRsp);
1148 EXPECT_CMD_PACKET_OUT(
1149 test_device(), kInquiry, &kInquiryRsp, &kExtendedInquiryResult);
1150
1151 std::unique_ptr<BrEdrDiscoverySession> session;
1152 size_t peers_found = 0u;
1153
1154 discovery_manager()->RequestDiscovery([&session, &peers_found](
1155 auto status, auto cb_session) {
1156 EXPECT_EQ(fit::ok(), status);
1157 cb_session->set_result_callback([&peers_found](auto&) { peers_found++; });
1158 session = std::move(cb_session);
1159 });
1160 RunUntilIdle();
1161 session = nullptr;
1162
1163 EXPECT_EQ(1u, peers_found);
1164 ASSERT_EQ(peer, peer_cache()->FindByAddress(kDeviceAddress3));
1165 EXPECT_EQ(TechnologyType::kDualMode, peer->technology());
1166 EXPECT_TRUE(peer->connectable());
1167
1168 test_device()->SendCommandChannelPacket(kInquiryComplete);
1169
1170 RunUntilIdle();
1171 }
1172
1173 // Verify that receiving an extended inquiry response with RSSI for a known LE
1174 // non-connectable peer results in the peer being changed to DualMode and
1175 // connectable.
TEST_F(BrEdrDiscoveryManagerTest,RSSIInquiryResultUpgradesKnownLowEnergyPeer)1176 TEST_F(BrEdrDiscoveryManagerTest, RSSIInquiryResultUpgradesKnownLowEnergyPeer) {
1177 Peer* peer = peer_cache()->NewPeer(kLeAliasAddress2, /*connectable=*/false);
1178 ASSERT_TRUE(peer);
1179 ASSERT_FALSE(peer->connectable());
1180 ASSERT_EQ(TechnologyType::kLowEnergy, peer->technology());
1181
1182 NewDiscoveryManager(pw::bluetooth::emboss::InquiryMode::EXTENDED);
1183
1184 EXPECT_CMD_PACKET_OUT(test_device(), kSetExtendedMode, &kSetExtendedModeRsp);
1185 EXPECT_CMD_PACKET_OUT(
1186 test_device(), kInquiry, &kInquiryRsp, &kRSSIInquiryResult);
1187 EXPECT_CMD_PACKET_OUT(test_device(),
1188 kRemoteNameRequest2,
1189 &kRemoteNameRequestRsp,
1190 &kRemoteNameRequestComplete2);
1191
1192 std::unique_ptr<BrEdrDiscoverySession> session;
1193 size_t peers_found = 0u;
1194
1195 discovery_manager()->RequestDiscovery([&session, &peers_found](
1196 auto status, auto cb_session) {
1197 EXPECT_EQ(fit::ok(), status);
1198 cb_session->set_result_callback([&peers_found](auto&) { peers_found++; });
1199 session = std::move(cb_session);
1200 });
1201 RunUntilIdle();
1202 session = nullptr;
1203
1204 EXPECT_EQ(1u, peers_found);
1205 ASSERT_EQ(peer, peer_cache()->FindByAddress(kDeviceAddress2));
1206 EXPECT_EQ(TechnologyType::kDualMode, peer->technology());
1207 EXPECT_TRUE(peer->connectable());
1208
1209 test_device()->SendCommandChannelPacket(kInquiryComplete);
1210
1211 RunUntilIdle();
1212 }
1213
1214 #ifndef NINSPECT
TEST_F(BrEdrDiscoveryManagerTest,Inspect)1215 TEST_F(BrEdrDiscoveryManagerTest, Inspect) {
1216 inspect::Inspector inspector;
1217 discovery_manager()->AttachInspect(inspector.GetRoot(),
1218 "bredr_discovery_manager");
1219
1220 auto discoverable_session_active_matcher =
1221 Contains(UintIs("discoverable_sessions", 1));
1222
1223 std::unique_ptr<BrEdrDiscoverableSession> discoverable_session;
1224 auto session_cb = [&discoverable_session](auto status, auto cb_session) {
1225 EXPECT_EQ(fit::ok(), status);
1226 discoverable_session = std::move(cb_session);
1227 };
1228
1229 EXPECT_CMD_PACKET_OUT(
1230 test_device(), kReadScanEnable, &kReadScanEnableRspPage);
1231 EXPECT_CMD_PACKET_OUT(
1232 test_device(), kWriteScanEnableBoth, &kWriteScanEnableRsp);
1233 discovery_manager()->RequestDiscoverable(session_cb);
1234 RunUntilIdle();
1235 EXPECT_TRUE(discoverable_session);
1236
1237 auto properties = inspect::ReadFromVmo(inspector.DuplicateVmo())
1238 .take_value()
1239 .take_children()
1240 .front()
1241 .node_ptr()
1242 ->take_properties();
1243 EXPECT_THAT(properties, discoverable_session_active_matcher);
1244
1245 auto discoverable_session_counted_matcher =
1246 ::testing::IsSupersetOf({UintIs("discoverable_sessions", 0),
1247 UintIs("discoverable_sessions_count", 1),
1248 UintIs("last_discoverable_length_sec", 4)});
1249
1250 RunFor(std::chrono::seconds(4));
1251 discoverable_session = nullptr;
1252 EXPECT_CMD_PACKET_OUT(
1253 test_device(), kReadScanEnable, &kReadScanEnableRspBoth);
1254 EXPECT_CMD_PACKET_OUT(
1255 test_device(), kWriteScanEnablePage, &kWriteScanEnableRsp);
1256 RunUntilIdle();
1257
1258 properties = inspect::ReadFromVmo(inspector.DuplicateVmo())
1259 .take_value()
1260 .take_children()
1261 .front()
1262 .node_ptr()
1263 ->take_properties();
1264 EXPECT_THAT(properties, discoverable_session_counted_matcher);
1265
1266 auto discovery_session_active_matcher =
1267 Contains(UintIs("discovery_sessions", 1));
1268
1269 std::unique_ptr<BrEdrDiscoverySession> discovery_session;
1270
1271 discovery_manager()->RequestDiscovery(
1272 [&discovery_session](auto status, auto cb_session) {
1273 EXPECT_EQ(fit::ok(), status);
1274 discovery_session = std::move(cb_session);
1275 });
1276
1277 EXPECT_CMD_PACKET_OUT(test_device(), kInquiry, &kInquiryRsp);
1278 RunUntilIdle();
1279 EXPECT_TRUE(discovery_session);
1280
1281 properties = inspect::ReadFromVmo(inspector.DuplicateVmo())
1282 .take_value()
1283 .take_children()
1284 .front()
1285 .node_ptr()
1286 ->take_properties();
1287 EXPECT_THAT(properties, discovery_session_active_matcher);
1288
1289 auto discovery_session_counted_matcher =
1290 ::testing::IsSupersetOf({UintIs("discovery_sessions", 0),
1291 UintIs("discovery_sessions_count", 1),
1292 UintIs("last_discovery_length_sec", 7)});
1293
1294 RunFor(std::chrono::seconds(7));
1295 discovery_session = nullptr;
1296 RunUntilIdle();
1297 test_device()->SendCommandChannelPacket(kInquiryComplete);
1298 RunUntilIdle();
1299
1300 properties = inspect::ReadFromVmo(inspector.DuplicateVmo())
1301 .take_value()
1302 .take_children()
1303 .front()
1304 .node_ptr()
1305 ->take_properties();
1306 EXPECT_THAT(properties, discovery_session_counted_matcher);
1307 }
1308 #endif // NINSPECT
1309
1310 } // namespace
1311 } // namespace bt::gap
1312