1 /*
2 * Copyright 2021 HIMSA II K/S - www.himsa.com.
3 * Represented by EHIMA - www.ehima.com
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <base/bind.h>
19 #include <base/bind_helpers.h>
20 #include <base/strings/string_number_conversions.h>
21 #include <gmock/gmock.h>
22 #include <gtest/gtest.h>
23 #include <osi/include/alarm.h>
24 #include <sys/socket.h>
25
26 #include <variant>
27
28 #include "bta/le_audio/le_audio_types.h"
29 #include "bta_csis_api.h"
30 #include "bta_gatt_api_mock.h"
31 #include "bta_gatt_queue_mock.h"
32 #include "bta_has_api.h"
33 #include "btif_storage_mock.h"
34 #include "btm_api_mock.h"
35 #include "gatt/database_builder.h"
36 #include "hardware/bt_gatt_types.h"
37 #include "has_types.h"
38 #include "mock_controller.h"
39 #include "mock_csis_client.h"
40
gatt_profile_get_eatt_support(const RawAddress & addr)41 bool gatt_profile_get_eatt_support(const RawAddress& addr) { return true; }
42 void osi_property_set_bool(const char* key, bool value);
43
44 std::map<std::string, int> mock_function_count_map;
45
46 namespace bluetooth {
47 namespace has {
48 namespace internal {
49 namespace {
50
51 using base::HexEncode;
52
53 using ::bluetooth::csis::CsisClient;
54 using ::bluetooth::has::ConnectionState;
55 using ::bluetooth::has::ErrorCode;
56 using ::bluetooth::has::HasClientCallbacks;
57 using ::bluetooth::has::PresetInfo;
58
59 using ::le_audio::has::HasClient;
60 using ::le_audio::has::HasCtpGroupOpCoordinator;
61 using ::le_audio::has::HasCtpOp;
62 using ::le_audio::has::HasDevice;
63 using ::le_audio::has::HasPreset;
64
65 using ::testing::_;
66 using ::testing::AnyNumber;
67 using ::testing::DoAll;
68 using ::testing::DoDefault;
69 using ::testing::Invoke;
70 using ::testing::Mock;
71 using ::testing::NotNull;
72 using ::testing::Return;
73 using ::testing::SaveArg;
74 using ::testing::Sequence;
75 using ::testing::SetArgPointee;
76 using ::testing::WithArg;
77
78 // Disables most likely false-positives from base::SplitString()
79 // extern "C" const char* __asan_default_options() {
80 // return "detect_container_overflow=0";
81 // }
82
GetTestAddress(int index)83 RawAddress GetTestAddress(int index) {
84 CHECK_LT(index, UINT8_MAX);
85 RawAddress result = {
86 {0xC0, 0xDE, 0xC0, 0xDE, 0x00, static_cast<uint8_t>(index)}};
87 return result;
88 }
89
GetTestConnId(const RawAddress & address)90 static uint16_t GetTestConnId(const RawAddress& address) {
91 return address.address[RawAddress::kLength - 1];
92 }
93
94 class MockHasCallbacks : public HasClientCallbacks {
95 public:
96 MockHasCallbacks() = default;
97 MockHasCallbacks(const MockHasCallbacks&) = delete;
98 MockHasCallbacks& operator=(const MockHasCallbacks&) = delete;
99
100 ~MockHasCallbacks() override = default;
101
102 MOCK_METHOD((void), OnConnectionState,
103 (ConnectionState state, const RawAddress& address), (override));
104 MOCK_METHOD((void), OnDeviceAvailable,
105 (const RawAddress& address, uint8_t features), (override));
106 MOCK_METHOD((void), OnFeaturesUpdate,
107 (const RawAddress& address, uint8_t features), (override));
108 MOCK_METHOD((void), OnActivePresetSelected,
109 ((std::variant<RawAddress, int> addr_or_group_id),
110 uint8_t preset_index),
111 (override));
112 MOCK_METHOD((void), OnActivePresetSelectError,
113 ((std::variant<RawAddress, int> addr_or_group_id),
114 ErrorCode result),
115 (override));
116 MOCK_METHOD((void), OnPresetInfo,
117 ((std::variant<RawAddress, int> addr_or_group_id),
118 PresetInfoReason change_id,
119 std::vector<PresetInfo> preset_change_records),
120 (override));
121 MOCK_METHOD((void), OnPresetInfoError,
122 ((std::variant<RawAddress, int> addr_or_group_id),
123 uint8_t preset_index, ErrorCode error_code),
124 (override));
125 MOCK_METHOD((void), OnSetPresetNameError,
126 ((std::variant<RawAddress, int> addr_or_group_id),
127 uint8_t preset_index, ErrorCode error_code),
128 (override));
129 };
130
131 class HasClientTestBase : public ::testing::Test {
132 protected:
133 std::map<uint16_t, uint8_t> current_peer_active_preset_idx_;
134 std::map<uint16_t, uint8_t> current_peer_features_val_;
135 std::map<uint16_t, std::set<HasPreset, HasPreset::ComparatorDesc>>
136 current_peer_presets_;
137
138 struct HasDbBuilder {
139 bool has;
140
141 static constexpr uint16_t kGapSvcStartHdl = 0x0001;
142 static constexpr uint16_t kGapDeviceNameValHdl = 0x0003;
143 static constexpr uint16_t kGapSvcEndHdl = kGapDeviceNameValHdl;
144
145 static constexpr uint16_t kSvcStartHdl = 0x0010;
146 static constexpr uint16_t kFeaturesValHdl = 0x0012;
147 static constexpr uint16_t kPresetsCtpValHdl = 0x0015;
148 static constexpr uint16_t kActivePresetIndexValHdl = 0x0018;
149 static constexpr uint16_t kSvcEndHdl = 0x001E;
150
151 static constexpr uint16_t kGattSvcStartHdl = 0x0090;
152 static constexpr uint16_t kGattSvcChangedValHdl = 0x0092;
153 static constexpr uint16_t kGattSvcEndHdl = kGattSvcChangedValHdl + 1;
154
155 bool features;
156 bool features_ntf;
157
158 bool preset_cp;
159 bool preset_cp_ntf;
160 bool preset_cp_ind;
161
162 bool active_preset_idx;
163 bool active_preset_idx_ntf;
164
Buildbluetooth::has::internal::__anon99444c580111::HasClientTestBase::HasDbBuilder165 const gatt::Database Build() {
166 gatt::DatabaseBuilder bob;
167
168 /* Generic Access Service */
169 bob.AddService(kGapSvcStartHdl, kGapSvcEndHdl, Uuid::From16Bit(0x1800),
170 true);
171 /* Device Name Char. */
172 bob.AddCharacteristic(kGapDeviceNameValHdl - 1, kGapDeviceNameValHdl,
173 Uuid::From16Bit(0x2a00), GATT_CHAR_PROP_BIT_READ);
174
175 /* 0x0004-0x000f left empty on purpose */
176 if (has) {
177 bob.AddService(kSvcStartHdl, kSvcEndHdl,
178 ::le_audio::has::kUuidHearingAccessService, true);
179
180 if (features) {
181 bob.AddCharacteristic(
182 kFeaturesValHdl - 1, kFeaturesValHdl,
183 ::le_audio::has::kUuidHearingAidFeatures,
184 GATT_CHAR_PROP_BIT_READ |
185 (features_ntf ? GATT_CHAR_PROP_BIT_NOTIFY : 0));
186
187 if (features_ntf) {
188 bob.AddDescriptor(kFeaturesValHdl + 1,
189 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
190 }
191 }
192
193 if (preset_cp) {
194 bob.AddCharacteristic(
195 kPresetsCtpValHdl - 1, kPresetsCtpValHdl,
196 ::le_audio::has::kUuidHearingAidPresetControlPoint,
197 GATT_CHAR_PROP_BIT_WRITE |
198 (preset_cp_ntf ? GATT_CHAR_PROP_BIT_NOTIFY : 0) |
199 (preset_cp_ind ? GATT_CHAR_PROP_BIT_INDICATE : 0));
200
201 if (preset_cp_ntf || preset_cp_ind) {
202 bob.AddDescriptor(kPresetsCtpValHdl + 1,
203 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
204 }
205 }
206
207 if (active_preset_idx) {
208 bob.AddCharacteristic(
209 kActivePresetIndexValHdl - 1, kActivePresetIndexValHdl,
210 ::le_audio::has::kUuidActivePresetIndex,
211 GATT_CHAR_PROP_BIT_READ |
212 (active_preset_idx_ntf ? GATT_CHAR_PROP_BIT_NOTIFY : 0));
213
214 if (active_preset_idx_ntf)
215 bob.AddDescriptor(kActivePresetIndexValHdl + 1,
216 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
217 }
218 }
219
220 /* GATTS */
221 /* 0x001F-0x0090 left empty on purpose */
222 bob.AddService(kGattSvcStartHdl, kGattSvcEndHdl,
223 Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER), true);
224 bob.AddCharacteristic(kGattSvcChangedValHdl - 1, kGattSvcChangedValHdl,
225 Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD),
226 GATT_CHAR_PROP_BIT_NOTIFY);
227 bob.AddDescriptor(kGattSvcChangedValHdl + 1,
228 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
229 return bob.Build();
230 };
231 };
232
FindCharacteristicByValueHandle(const gatt::Service * svc,uint16_t handle)233 const gatt::Characteristic* FindCharacteristicByValueHandle(
234 const gatt::Service* svc, uint16_t handle) {
235 if (svc == nullptr) return nullptr;
236
237 auto it =
238 std::find_if(svc->characteristics.cbegin(), svc->characteristics.cend(),
239 [handle](const auto& characteristic) {
240 return characteristic.value_handle == handle;
241 });
242 return (it != svc->characteristics.cend()) ? &(*it) : nullptr;
243 }
244
set_sample_database(const RawAddress & address,HasDbBuilder & builder,uint8_t features_val=0x0,std::optional<std::set<HasPreset,HasPreset::ComparatorDesc>> presets_op=std::nullopt)245 void set_sample_database(
246 const RawAddress& address, HasDbBuilder& builder,
247 uint8_t features_val = 0x0,
248 std::optional<std::set<HasPreset, HasPreset::ComparatorDesc>> presets_op =
249 std::nullopt) {
250 uint16_t conn_id = GetTestConnId(address);
251
252 /* For some test cases these defaults are enough */
253 if (!presets_op)
254 presets_op = {{
255 HasPreset(6, HasPreset::kPropertyAvailable, "Universal"),
256 HasPreset(
257 55, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
258 "YourPreset55"),
259 }};
260 auto& presets = presets_op.value();
261 auto const active_preset = presets.begin();
262
263 services_map[conn_id] = builder.Build().Services();
264 current_peer_features_val_.insert_or_assign(conn_id, features_val);
265 current_peer_active_preset_idx_.insert_or_assign(conn_id,
266 active_preset->GetIndex());
267 current_peer_presets_.insert_or_assign(conn_id, std::move(presets));
268
269 ON_CALL(gatt_queue, ReadCharacteristic(conn_id, _, _, _))
270 .WillByDefault(Invoke([this](uint16_t conn_id, uint16_t handle,
271 GATT_READ_OP_CB cb, void* cb_data) {
272 auto* svc = gatt::FindService(services_map[conn_id], handle);
273 if (svc == nullptr) return;
274
275 std::vector<uint8_t> value;
276 tGATT_STATUS status = GATT_SUCCESS;
277
278 switch (handle) {
279 case HasDbBuilder::kGapDeviceNameValHdl:
280 value.resize(20);
281 break;
282 case HasDbBuilder::kFeaturesValHdl:
283 value.resize(1);
284 value[0] = current_peer_features_val_.at(conn_id);
285 break;
286 case HasDbBuilder::kActivePresetIndexValHdl:
287 value.resize(1);
288 value[0] = current_peer_active_preset_idx_.at(conn_id);
289 break;
290 case HasDbBuilder::kPresetsCtpValHdl:
291 /* passthrough */
292 default:
293 status = GATT_READ_NOT_PERMIT;
294 break;
295 }
296
297 if (cb)
298 cb(conn_id, status, handle, value.size(), value.data(), cb_data);
299 }));
300
301 /* Default action for the Control Point operation writes */
302 ON_CALL(gatt_queue,
303 WriteCharacteristic(conn_id, HasDbBuilder::kPresetsCtpValHdl, _,
304 GATT_WRITE, _, _))
305 .WillByDefault(Invoke([this, address](uint16_t conn_id, uint16_t handle,
306 std::vector<uint8_t> value,
307 tGATT_WRITE_TYPE write_type,
308 GATT_WRITE_OP_CB cb,
309 void* cb_data) {
310 auto pp = value.data();
311 auto len = value.size();
312 uint8_t op, index, num_of_indices;
313
314 const bool indicate = false;
315
316 if (len < 1) {
317 if (cb)
318 cb(conn_id, GATT_INVALID_ATTR_LEN, handle, value.size(),
319 value.data(), cb_data);
320 return;
321 }
322
323 STREAM_TO_UINT8(op, pp)
324 --len;
325 if (op >
326 static_cast<
327 std::underlying_type_t<::le_audio::has::PresetCtpOpcode>>(
328 ::le_audio::has::PresetCtpOpcode::OP_MAX_)) {
329 /* Invalid Opcode */
330 if (cb)
331 cb(conn_id, (tGATT_STATUS)0x80, handle, value.size(),
332 value.data(), cb_data);
333 return;
334 }
335
336 switch (static_cast<::le_audio::has::PresetCtpOpcode>(op)) {
337 case ::le_audio::has::PresetCtpOpcode::READ_PRESETS:
338 if (len < 2) {
339 if (cb)
340 cb(conn_id, GATT_INVALID_ATTR_LEN, handle, value.size(),
341 value.data(), cb_data);
342
343 } else {
344 STREAM_TO_UINT8(index, pp);
345 STREAM_TO_UINT8(num_of_indices, pp);
346 len -= 2;
347 ASSERT_EQ(0u, len);
348
349 InjectNotifyReadPresetsResponse(conn_id, address, handle, value,
350 indicate, index, num_of_indices,
351 cb, cb_data);
352 }
353 break;
354
355 case ::le_audio::has::PresetCtpOpcode::SET_ACTIVE_PRESET: {
356 if (len < 1) {
357 if (cb)
358 cb(conn_id, GATT_INVALID_ATTR_LEN, handle, value.size(),
359 value.data(), cb_data);
360 break;
361 }
362 STREAM_TO_UINT8(index, pp);
363 --len;
364 ASSERT_EQ(0u, len);
365
366 auto presets = current_peer_presets_.at(conn_id);
367 if (presets.count(index)) {
368 current_peer_active_preset_idx_.insert_or_assign(conn_id,
369 index);
370 if (cb)
371 cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(),
372 cb_data);
373 InjectActivePresetNotification(conn_id, address, handle, value,
374 index, cb, cb_data);
375 } else {
376 /* Preset Operation Not Possible */
377 if (cb)
378 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(),
379 value.data(), cb_data);
380 }
381 } break;
382
383 case ::le_audio::has::PresetCtpOpcode::SET_ACTIVE_PRESET_SYNC: {
384 auto features = current_peer_features_val_.at(conn_id);
385 if ((features & ::bluetooth::has::
386 kFeatureBitPresetSynchronizationSupported) ==
387 0) {
388 /* Synchronization Not Supported */
389 if (cb)
390 cb(conn_id, (tGATT_STATUS)0x82, handle, value.size(),
391 value.data(), cb_data);
392 break;
393 }
394
395 if (len < 1) {
396 if (cb)
397 cb(conn_id, GATT_INVALID_ATTR_LEN, handle, value.size(),
398 value.data(), cb_data);
399 break;
400 }
401 STREAM_TO_UINT8(index, pp);
402 --len;
403 ASSERT_EQ(0u, len);
404
405 auto csis_api = CsisClient::Get();
406 int group_id = bluetooth::groups::kGroupUnknown;
407 if (csis_api != nullptr) {
408 group_id = csis_api->GetGroupId(
409 address, ::le_audio::uuid::kCapServiceUuid);
410 }
411
412 if (group_id != bluetooth::groups::kGroupUnknown) {
413 if (cb)
414 cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(),
415 cb_data);
416 /* Send notification from all grouped devices */
417 auto addresses = csis_api->GetDeviceList(group_id);
418 for (auto& addr : addresses) {
419 auto conn = GetTestConnId(addr);
420 InjectActivePresetNotification(conn, addr, handle, value,
421 index, cb, cb_data);
422 }
423 } else {
424 /* Preset Operation Not Possible */
425 if (cb)
426 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(),
427 value.data(), cb_data);
428 }
429 } break;
430
431 case ::le_audio::has::PresetCtpOpcode::SET_NEXT_PRESET: {
432 ASSERT_EQ(0u, len);
433 ASSERT_NE(0u, current_peer_active_preset_idx_.count(conn_id));
434 ASSERT_NE(0u, current_peer_presets_.count(conn_id));
435
436 auto current_preset = current_peer_active_preset_idx_.at(conn_id);
437 auto presets = current_peer_presets_.at(conn_id);
438 auto current = presets.find(current_preset);
439 if (current != presets.end()) {
440 ++current;
441 if (current == presets.end()) current = presets.begin();
442
443 current_peer_active_preset_idx_.insert_or_assign(
444 conn_id, current->GetIndex());
445 InjectActivePresetNotification(conn_id, address, handle, value,
446 current->GetIndex(), cb,
447 cb_data);
448
449 } else {
450 /* Preset Operation Not Possible */
451 if (cb)
452 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(),
453 value.data(), cb_data);
454 }
455 } break;
456
457 case ::le_audio::has::PresetCtpOpcode::SET_PREV_PRESET: {
458 ASSERT_EQ(0u, len);
459 ASSERT_NE(0u, current_peer_active_preset_idx_.count(conn_id));
460 ASSERT_NE(0u, current_peer_presets_.count(conn_id));
461
462 auto current_preset = current_peer_active_preset_idx_.at(conn_id);
463 auto presets = current_peer_presets_.at(conn_id);
464 auto rit = presets.rbegin();
465 while (rit != presets.rend()) {
466 if (rit->GetIndex() == current_preset) {
467 rit++;
468 /* Wrap around */
469 if (rit == presets.rend()) {
470 rit = presets.rbegin();
471 }
472 break;
473 }
474 rit++;
475 }
476
477 if (rit != presets.rend()) {
478 if (cb)
479 cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(),
480 cb_data);
481 current_peer_active_preset_idx_.insert_or_assign(
482 conn_id, rit->GetIndex());
483 InjectActivePresetNotification(conn_id, address, handle, value,
484 rit->GetIndex(), cb, cb_data);
485 } else {
486 /* Preset Operation Not Possible */
487 if (cb)
488 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(),
489 value.data(), cb_data);
490 }
491 } break;
492
493 case ::le_audio::has::PresetCtpOpcode::SET_NEXT_PRESET_SYNC: {
494 ASSERT_EQ(0u, len);
495 auto features = current_peer_features_val_.at(conn_id);
496 if ((features & ::bluetooth::has::
497 kFeatureBitPresetSynchronizationSupported) ==
498 0) {
499 /* Synchronization Not Supported */
500 if (cb)
501 cb(conn_id, (tGATT_STATUS)0x82, handle, value.size(),
502 value.data(), cb_data);
503 break;
504 }
505
506 auto current_preset = current_peer_active_preset_idx_.at(conn_id);
507 auto presets = current_peer_presets_.at(conn_id);
508 auto rit = presets.begin();
509 while (rit != presets.end()) {
510 if (rit->GetIndex() == current_preset) {
511 rit++;
512 /* Wrap around */
513 if (rit == presets.end()) {
514 rit = presets.begin();
515 }
516 break;
517 }
518 rit++;
519 }
520
521 if (rit != presets.end()) {
522 auto synced_group = mock_csis_client_module_.GetGroupId(
523 GetTestAddress(conn_id), ::le_audio::uuid::kCapServiceUuid);
524 auto addresses =
525 mock_csis_client_module_.GetDeviceList(synced_group);
526
527 // Emulate locally synced op. - notify from all of the devices
528 for (auto addr : addresses) {
529 auto cid = GetTestConnId(addr);
530 if ((cid == conn_id) && (cb != nullptr))
531 cb(cid, GATT_SUCCESS, handle, value.size(), value.data(),
532 cb_data);
533
534 current_peer_active_preset_idx_.insert_or_assign(
535 conn_id, rit->GetIndex());
536 InjectActivePresetNotification(cid, addr, handle, value,
537 rit->GetIndex(), cb, cb_data);
538 }
539 } else {
540 /* Preset Operation Not Possible */
541 if (cb)
542 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(),
543 value.data(), cb_data);
544 }
545 } break;
546
547 case ::le_audio::has::PresetCtpOpcode::SET_PREV_PRESET_SYNC: {
548 ASSERT_EQ(0u, len);
549 auto features = current_peer_features_val_.at(conn_id);
550 if ((features & ::bluetooth::has::
551 kFeatureBitPresetSynchronizationSupported) ==
552 0) {
553 /* Synchronization Not Supported */
554 if (cb)
555 cb(conn_id, (tGATT_STATUS)0x82, handle, value.size(),
556 value.data(), cb_data);
557 break;
558 }
559
560 auto current_preset = current_peer_active_preset_idx_.at(conn_id);
561 auto presets = current_peer_presets_.at(conn_id);
562 auto rit = presets.rbegin();
563 while (rit != presets.rend()) {
564 if (rit->GetIndex() == current_preset) {
565 rit++;
566 /* Wrap around */
567 if (rit == presets.rend()) {
568 rit = presets.rbegin();
569 }
570 break;
571 }
572 rit++;
573 }
574
575 if (rit != presets.rend()) {
576 auto synced_group = mock_csis_client_module_.GetGroupId(
577 GetTestAddress(conn_id), ::le_audio::uuid::kCapServiceUuid);
578 auto addresses =
579 mock_csis_client_module_.GetDeviceList(synced_group);
580
581 // Emulate locally synced op. - notify from all of the devices
582 for (auto addr : addresses) {
583 auto cid = GetTestConnId(addr);
584 if ((cid == conn_id) && (cb != nullptr))
585 cb(cid, GATT_SUCCESS, handle, value.size(), value.data(),
586 cb_data);
587
588 current_peer_active_preset_idx_.insert_or_assign(
589 conn_id, rit->GetIndex());
590 InjectActivePresetNotification(cid, addr, handle, value,
591 rit->GetIndex(), cb, cb_data);
592 }
593 } else {
594 /* Preset Operation Not Possible */
595 if (cb)
596 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(),
597 value.data(), cb_data);
598 }
599 } break;
600
601 case ::le_audio::has::PresetCtpOpcode::WRITE_PRESET_NAME: {
602 STREAM_TO_UINT8(index, pp);
603 --len;
604 auto name = std::string(pp, pp + len);
605 len = 0;
606
607 ASSERT_NE(0u, current_peer_presets_.count(conn_id));
608 auto presets = current_peer_presets_.at(conn_id);
609 auto rit = presets.rbegin();
610 auto current = rit;
611 while (rit != presets.rend()) {
612 if (rit->GetIndex() == index) {
613 current = rit;
614 rit++;
615 break;
616 }
617 rit++;
618 }
619
620 auto prev_index = (rit == presets.rend()) ? 0 : rit->GetIndex();
621
622 ASSERT_NE(current, presets.rend());
623 if (cb)
624 cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(),
625 cb_data);
626
627 auto new_preset = HasPreset(current->GetIndex(),
628 current->GetProperties(), name);
629 presets.erase(current->GetIndex());
630 presets.insert(new_preset);
631
632 InjectPresetChanged(
633 conn_id, address, indicate, new_preset, prev_index,
634 ::le_audio::has::PresetCtpChangeId::PRESET_GENERIC_UPDATE,
635 true);
636 } break;
637
638 default:
639 if (cb)
640 cb(conn_id, GATT_INVALID_HANDLE, handle, value.size(),
641 value.data(), cb_data);
642 break;
643 }
644 }));
645 }
646
SetUp(void)647 void SetUp(void) override {
648 mock_function_count_map.clear();
649 controller::SetMockControllerInterface(&controller_interface_);
650 bluetooth::manager::SetMockBtmInterface(&btm_interface);
651 bluetooth::storage::SetMockBtifStorageInterface(&btif_storage_interface_);
652 gatt::SetMockBtaGattInterface(&gatt_interface);
653 gatt::SetMockBtaGattQueue(&gatt_queue);
654 callbacks.reset(new MockHasCallbacks());
655
656 encryption_result = true;
657
658 MockCsisClient::SetMockInstanceForTesting(&mock_csis_client_module_);
659 ON_CALL(mock_csis_client_module_, Get())
660 .WillByDefault(Return(&mock_csis_client_module_));
661 ON_CALL(mock_csis_client_module_, IsCsisClientRunning())
662 .WillByDefault(Return(true));
663
664 /* default action for GetCharacteristic function call */
665 ON_CALL(gatt_interface, GetCharacteristic(_, _))
666 .WillByDefault(
667 Invoke([&](uint16_t conn_id,
668 uint16_t handle) -> const gatt::Characteristic* {
669 std::list<gatt::Service>& services = services_map[conn_id];
670 for (auto const& service : services) {
671 for (auto const& characteristic : service.characteristics) {
672 if (characteristic.value_handle == handle) {
673 return &characteristic;
674 }
675 }
676 }
677
678 return nullptr;
679 }));
680
681 /* default action for GetOwningService function call */
682 ON_CALL(gatt_interface, GetOwningService(_, _))
683 .WillByDefault(Invoke(
684 [&](uint16_t conn_id, uint16_t handle) -> const gatt::Service* {
685 std::list<gatt::Service>& services = services_map[conn_id];
686 for (auto const& service : services) {
687 if (service.handle <= handle && service.end_handle >= handle) {
688 return &service;
689 }
690 }
691
692 return nullptr;
693 }));
694
695 ON_CALL(gatt_interface, ServiceSearchRequest(_, _))
696 .WillByDefault(WithArg<0>(Invoke(
697 [&](uint16_t conn_id) { InjectSearchCompleteEvent(conn_id); })));
698
699 /* default action for GetServices function call */
700 ON_CALL(gatt_interface, GetServices(_))
701 .WillByDefault(WithArg<0>(
702 Invoke([&](uint16_t conn_id) -> std::list<gatt::Service>* {
703 return &services_map[conn_id];
704 })));
705
706 /* default action for RegisterForNotifications function call */
707 ON_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _))
708 .WillByDefault(Return(GATT_SUCCESS));
709
710 /* default action for DeregisterForNotifications function call */
711 ON_CALL(gatt_interface, DeregisterForNotifications(gatt_if, _, _))
712 .WillByDefault(Return(GATT_SUCCESS));
713
714 /* default action for WriteDescriptor function call */
715 ON_CALL(gatt_queue, WriteDescriptor(_, _, _, _, _, _))
716 .WillByDefault(
717 Invoke([](uint16_t conn_id, uint16_t handle,
718 std::vector<uint8_t> value, tGATT_WRITE_TYPE write_type,
719 GATT_WRITE_OP_CB cb, void* cb_data) -> void {
720 if (cb)
721 cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(),
722 cb_data);
723 }));
724
725 /* by default connect only direct connection requests */
726 ON_CALL(gatt_interface, Open(_, _, _, _))
727 .WillByDefault(
728 Invoke([&](tGATT_IF client_if, const RawAddress& remote_bda,
729 tBTM_BLE_CONN_TYPE connection_type, bool opportunistic) {
730 if (connection_type == BTM_BLE_DIRECT_CONNECTION)
731 InjectConnectedEvent(remote_bda, GetTestConnId(remote_bda));
732 }));
733
734 ON_CALL(gatt_interface, Close(_))
735 .WillByDefault(Invoke(
736 [&](uint16_t conn_id) { InjectDisconnectedEvent(conn_id); }));
737 }
738
TearDown(void)739 void TearDown(void) override {
740 services_map.clear();
741 gatt::SetMockBtaGattQueue(nullptr);
742 gatt::SetMockBtaGattInterface(nullptr);
743 bluetooth::storage::SetMockBtifStorageInterface(nullptr);
744 bluetooth::manager::SetMockBtmInterface(nullptr);
745 controller::SetMockControllerInterface(nullptr);
746 callbacks.reset();
747
748 current_peer_active_preset_idx_.clear();
749 current_peer_features_val_.clear();
750 }
751
TestAppRegister(void)752 void TestAppRegister(void) {
753 BtaAppRegisterCallback app_register_callback;
754 EXPECT_CALL(gatt_interface, AppRegister(_, _, _))
755 .WillOnce(DoAll(SaveArg<0>(&gatt_callback),
756 SaveArg<1>(&app_register_callback)));
757 HasClient::Initialize(callbacks.get(), base::DoNothing());
758 ASSERT_TRUE(gatt_callback);
759 ASSERT_TRUE(app_register_callback);
760 app_register_callback.Run(gatt_if, GATT_SUCCESS);
761 ASSERT_TRUE(HasClient::IsHasClientRunning());
762 Mock::VerifyAndClearExpectations(&gatt_interface);
763 }
764
TestAppUnregister(void)765 void TestAppUnregister(void) {
766 EXPECT_CALL(gatt_interface, AppDeregister(gatt_if));
767 HasClient::CleanUp();
768 ASSERT_FALSE(HasClient::IsHasClientRunning());
769 gatt_callback = nullptr;
770 }
771
TestConnect(const RawAddress & address)772 void TestConnect(const RawAddress& address) {
773 ON_CALL(btm_interface, BTM_IsEncrypted(address, _))
774 .WillByDefault(DoAll(Return(encryption_result)));
775
776 EXPECT_CALL(gatt_interface,
777 Open(gatt_if, address, BTM_BLE_DIRECT_CONNECTION, _));
778 HasClient::Get()->Connect(address);
779
780 Mock::VerifyAndClearExpectations(&*callbacks);
781 Mock::VerifyAndClearExpectations(&gatt_queue);
782 Mock::VerifyAndClearExpectations(&gatt_interface);
783 Mock::VerifyAndClearExpectations(&btm_interface);
784 }
785
TestDisconnect(const RawAddress & address,uint16_t conn_id)786 void TestDisconnect(const RawAddress& address, uint16_t conn_id) {
787 EXPECT_CALL(gatt_interface, CancelOpen(_, address, _)).Times(AnyNumber());
788 if (conn_id != GATT_INVALID_CONN_ID) {
789 assert(0);
790 EXPECT_CALL(gatt_interface, Close(conn_id));
791 } else {
792 EXPECT_CALL(gatt_interface, CancelOpen(gatt_if, address, _));
793 }
794 HasClient::Get()->Disconnect(address);
795 }
796
TestAddFromStorage(const RawAddress & address,uint8_t features,bool auto_connect)797 void TestAddFromStorage(const RawAddress& address, uint8_t features,
798 bool auto_connect) {
799 if (auto_connect) {
800 EXPECT_CALL(gatt_interface,
801 Open(gatt_if, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, _));
802 HasClient::Get()->AddFromStorage(address, features, auto_connect);
803
804 /* Inject connected event for autoconnect/background connection */
805 InjectConnectedEvent(address, GetTestConnId(address));
806 } else {
807 EXPECT_CALL(gatt_interface, Open(gatt_if, address, _, _)).Times(0);
808 HasClient::Get()->AddFromStorage(address, features, auto_connect);
809 }
810
811 Mock::VerifyAndClearExpectations(&gatt_interface);
812 }
813
InjectConnectedEvent(const RawAddress & address,uint16_t conn_id,tGATT_STATUS status=GATT_SUCCESS)814 void InjectConnectedEvent(const RawAddress& address, uint16_t conn_id,
815 tGATT_STATUS status = GATT_SUCCESS) {
816 tBTA_GATTC_OPEN event_data = {
817 .status = status,
818 .conn_id = conn_id,
819 .client_if = gatt_if,
820 .remote_bda = address,
821 .transport = GATT_TRANSPORT_LE,
822 .mtu = 240,
823 };
824
825 connected_devices[conn_id] = address;
826 gatt_callback(BTA_GATTC_OPEN_EVT, (tBTA_GATTC*)&event_data);
827 }
828
InjectDisconnectedEvent(uint16_t conn_id,tGATT_DISCONN_REASON reason=GATT_CONN_TERMINATE_LOCAL_HOST,bool allow_fake_conn=false)829 void InjectDisconnectedEvent(
830 uint16_t conn_id,
831 tGATT_DISCONN_REASON reason = GATT_CONN_TERMINATE_LOCAL_HOST,
832 bool allow_fake_conn = false) {
833 if (!allow_fake_conn) ASSERT_NE(connected_devices.count(conn_id), 0u);
834
835 tBTA_GATTC_CLOSE event_data = {
836 .status = GATT_SUCCESS,
837 .conn_id = conn_id,
838 .client_if = gatt_if,
839 .remote_bda = connected_devices[conn_id],
840 .reason = reason,
841 };
842
843 connected_devices.erase(conn_id);
844 gatt_callback(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC*)&event_data);
845 }
846
InjectSearchCompleteEvent(uint16_t conn_id)847 void InjectSearchCompleteEvent(uint16_t conn_id) {
848 tBTA_GATTC_SEARCH_CMPL event_data = {
849 .status = GATT_SUCCESS,
850 .conn_id = conn_id,
851 };
852
853 gatt_callback(BTA_GATTC_SEARCH_CMPL_EVT, (tBTA_GATTC*)&event_data);
854 }
855
InjectNotificationEvent(const RawAddress & test_address,uint16_t conn_id,uint16_t handle,std::vector<uint8_t> value,bool indicate=false)856 void InjectNotificationEvent(const RawAddress& test_address, uint16_t conn_id,
857 uint16_t handle, std::vector<uint8_t> value,
858 bool indicate = false) {
859 tBTA_GATTC_NOTIFY event_data = {
860 .conn_id = conn_id,
861 .bda = test_address,
862 .handle = handle,
863 .len = (uint8_t)value.size(),
864 .is_notify = !indicate,
865 };
866
867 ASSERT_TRUE(value.size() < GATT_MAX_ATTR_LEN);
868 std::copy(value.begin(), value.end(), event_data.value);
869 gatt_callback(BTA_GATTC_NOTIF_EVT, (tBTA_GATTC*)&event_data);
870 }
871
SetEncryptionResult(const RawAddress & address,bool success)872 void SetEncryptionResult(const RawAddress& address, bool success) {
873 encryption_result = success;
874 ON_CALL(btm_interface, BTM_IsEncrypted(address, _))
875 .WillByDefault(Return(success));
876 ON_CALL(btm_interface, GetSecurityFlagsByTransport(address, NotNull(), _))
877 .WillByDefault(
878 DoAll(SetArgPointee<1>(success ? BTM_SEC_FLAG_ENCRYPTED : 0),
879 Return(true)));
880 if (!success) {
881 EXPECT_CALL(btm_interface,
882 SetEncryption(address, _, NotNull(), _, BTM_BLE_SEC_ENCRYPT))
883 .WillOnce(Invoke(
884 [success](const RawAddress& bd_addr, tBT_TRANSPORT transport,
885 tBTM_SEC_CALLBACK* p_callback, void* p_ref_data,
886 tBTM_BLE_SEC_ACT sec_act) -> tBTM_STATUS {
887 p_callback(&bd_addr, transport, p_ref_data,
888 success ? BTM_SUCCESS : BTM_FAILED_ON_SECURITY);
889 return BTM_SUCCESS;
890 }));
891 }
892 }
893
InjectNotifyReadPresetResponse(uint16_t conn_id,RawAddress const & address,uint16_t handle,const HasPreset & preset,bool indicate,bool is_last)894 void InjectNotifyReadPresetResponse(uint16_t conn_id,
895 RawAddress const& address,
896 uint16_t handle, const HasPreset& preset,
897 bool indicate, bool is_last) {
898 std::vector<uint8_t> value;
899
900 value.push_back(
901 static_cast<std::underlying_type_t<::le_audio::has::PresetCtpOpcode>>(
902 ::le_audio::has::PresetCtpOpcode::READ_PRESET_RESPONSE));
903 value.push_back(is_last ? 0x01 : 0x00);
904
905 preset.ToCharacteristicValue(value);
906 InjectNotificationEvent(address, conn_id, handle, value, indicate);
907 }
908
InjectPresetChanged(uint16_t conn_id,RawAddress const & address,bool indicate,const HasPreset & preset,uint8_t prev_index,::le_audio::has::PresetCtpChangeId change_id,bool is_last)909 void InjectPresetChanged(uint16_t conn_id, RawAddress const& address,
910 bool indicate, const HasPreset& preset,
911 uint8_t prev_index,
912 ::le_audio::has::PresetCtpChangeId change_id,
913 bool is_last) {
914 std::vector<uint8_t> value;
915
916 value.push_back(
917 static_cast<std::underlying_type_t<::le_audio::has::PresetCtpOpcode>>(
918 ::le_audio::has::PresetCtpOpcode::PRESET_CHANGED));
919 value.push_back(static_cast<uint8_t>(change_id));
920 value.push_back(is_last ? 0x01 : 0x00);
921
922 switch (change_id) {
923 case ::le_audio::has::PresetCtpChangeId::PRESET_GENERIC_UPDATE:
924 value.push_back(prev_index);
925 preset.ToCharacteristicValue(value);
926 break;
927 case ::le_audio::has::PresetCtpChangeId::PRESET_DELETED:
928 case ::le_audio::has::PresetCtpChangeId::PRESET_AVAILABLE:
929 case ::le_audio::has::PresetCtpChangeId::PRESET_UNAVAILABLE:
930 default:
931 value.push_back(preset.GetIndex());
932 break;
933 }
934
935 InjectNotificationEvent(address, conn_id, HasDbBuilder::kPresetsCtpValHdl,
936 value, indicate);
937 }
938
InjectNotifyReadPresetsResponse(uint16_t conn_id,RawAddress const & address,uint16_t handle,std::vector<uint8_t> value,bool indicate,int index,int num_of_indices,GATT_WRITE_OP_CB cb,void * cb_data)939 void InjectNotifyReadPresetsResponse(
940 uint16_t conn_id, RawAddress const& address, uint16_t handle,
941 std::vector<uint8_t> value, bool indicate, int index, int num_of_indices,
942 GATT_WRITE_OP_CB cb, void* cb_data) {
943 auto presets = current_peer_presets_.at(conn_id);
944 LOG_ASSERT(!presets.empty()) << __func__ << " Mocking error!";
945
946 /* Index is a start index, not necessary is a valid index for the
947 * peer device */
948 auto preset = presets.find(index);
949 while (preset == presets.end() &&
950 index++ <= ::le_audio::has::kMaxNumOfPresets) {
951 preset = presets.find(index);
952 }
953
954 if (preset == presets.end()) {
955 /* operation not possible */
956 if (cb)
957 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(), value.data(),
958 cb_data);
959
960 return;
961 }
962
963 if (cb)
964 cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(), cb_data);
965 /* Notify presets */
966 int num_of_notif = 1;
967 while (1) {
968 bool last =
969 preset == std::prev(presets.end()) || num_of_notif == num_of_indices;
970 InjectNotifyReadPresetResponse(conn_id, address, handle, *preset,
971 indicate, (last));
972 if (last) return;
973
974 num_of_notif++;
975 preset++;
976 }
977 }
978
InjectActivePresetNotification(uint16_t conn_id,RawAddress const & address,uint16_t handle,std::vector<uint8_t> wr_value,uint8_t index,GATT_WRITE_OP_CB cb,void * cb_data)979 void InjectActivePresetNotification(uint16_t conn_id,
980 RawAddress const& address,
981 uint16_t handle,
982 std::vector<uint8_t> wr_value,
983 uint8_t index, GATT_WRITE_OP_CB cb,
984 void* cb_data) {
985 auto presets = current_peer_presets_.at(conn_id);
986 LOG_ASSERT(!presets.empty()) << __func__ << " Mocking error!";
987
988 auto preset = presets.find(index);
989 if (preset == presets.end()) {
990 /* preset operation not possible */
991 if (cb)
992 cb(conn_id, (tGATT_STATUS)0x83, handle, wr_value.size(),
993 wr_value.data(), cb_data);
994 return;
995 }
996
997 std::vector<uint8_t> value;
998 value.push_back(index);
999 InjectNotificationEvent(
1000 address, conn_id, HasDbBuilder::kActivePresetIndexValHdl, value, false);
1001 }
1002
SetSampleDatabaseHasNoFeatures(const RawAddress & address)1003 void SetSampleDatabaseHasNoFeatures(const RawAddress& address) {
1004 HasDbBuilder builder = {
1005 .has = true,
1006 .features = false,
1007 .features_ntf = false,
1008 .preset_cp = true,
1009 .preset_cp_ntf = false,
1010 .preset_cp_ind = true,
1011 .active_preset_idx = true,
1012 .active_preset_idx_ntf = true,
1013 };
1014 set_sample_database(address, builder);
1015 }
1016
SetSampleDatabaseHasNoPresetChange(const RawAddress & address,uint8_t features_value=0x00)1017 void SetSampleDatabaseHasNoPresetChange(const RawAddress& address,
1018 uint8_t features_value = 0x00) {
1019 HasDbBuilder builder = {
1020 .has = true,
1021 .features = true,
1022 .features_ntf = false,
1023 .preset_cp = false,
1024 .preset_cp_ntf = false,
1025 .preset_cp_ind = false,
1026 .active_preset_idx = false,
1027 .active_preset_idx_ntf = false,
1028 };
1029 set_sample_database(address, builder, features_value);
1030 }
1031
SetSampleDatabaseHasNoOptionalNtf(const RawAddress & address,uint8_t features=0x00)1032 void SetSampleDatabaseHasNoOptionalNtf(const RawAddress& address,
1033 uint8_t features = 0x00) {
1034 HasDbBuilder builder = {
1035 .has = true,
1036 .features = true,
1037 .features_ntf = false,
1038 .preset_cp = true,
1039 .preset_cp_ntf = false,
1040 .preset_cp_ind = true,
1041 .active_preset_idx = true,
1042 .active_preset_idx_ntf = true,
1043 };
1044 set_sample_database(address, builder, features);
1045 }
1046
SetSampleDatabaseNoHas(const RawAddress & address,uint8_t features=0x00)1047 void SetSampleDatabaseNoHas(const RawAddress& address,
1048 uint8_t features = 0x00) {
1049 HasDbBuilder builder = {
1050 .has = false,
1051 .features = false,
1052 .features_ntf = false,
1053 .preset_cp = false,
1054 .preset_cp_ntf = false,
1055 .preset_cp_ind = false,
1056 .active_preset_idx = true,
1057 .active_preset_idx_ntf = true,
1058 };
1059 set_sample_database(address, builder, features);
1060 }
1061
SetSampleDatabaseHasBrokenNoActivePreset(const RawAddress & address,uint8_t features=0x00)1062 void SetSampleDatabaseHasBrokenNoActivePreset(const RawAddress& address,
1063 uint8_t features = 0x00) {
1064 HasDbBuilder builder = {
1065 .has = true,
1066 .features = true,
1067 .features_ntf = false,
1068 .preset_cp = true,
1069 .preset_cp_ntf = true,
1070 .preset_cp_ind = true,
1071 .active_preset_idx = false,
1072 .active_preset_idx_ntf = false,
1073 };
1074 set_sample_database(address, builder, features);
1075 }
1076
SetSampleDatabaseHasBrokenNoActivePresetNtf(const RawAddress & address,uint8_t features=0x00)1077 void SetSampleDatabaseHasBrokenNoActivePresetNtf(const RawAddress& address,
1078 uint8_t features = 0x00) {
1079 HasDbBuilder builder = {
1080 .has = true,
1081 .features = true,
1082 .features_ntf = false,
1083 .preset_cp = true,
1084 .preset_cp_ntf = true,
1085 .preset_cp_ind = true,
1086 .active_preset_idx = true,
1087 .active_preset_idx_ntf = false,
1088 };
1089 set_sample_database(address, builder, features);
1090 }
1091
SetSampleDatabaseHasOnlyFeaturesNtf(const RawAddress & address,uint8_t features=0x00)1092 void SetSampleDatabaseHasOnlyFeaturesNtf(const RawAddress& address,
1093 uint8_t features = 0x00) {
1094 HasDbBuilder builder = {
1095 .has = true,
1096 .features = true,
1097 .features_ntf = true,
1098 .preset_cp = false,
1099 .preset_cp_ntf = false,
1100 .preset_cp_ind = false,
1101 .active_preset_idx = false,
1102 .active_preset_idx_ntf = false,
1103 };
1104 set_sample_database(address, builder, features);
1105 }
1106
SetSampleDatabaseHasOnlyFeaturesNoNtf(const RawAddress & address,uint8_t features=0x00)1107 void SetSampleDatabaseHasOnlyFeaturesNoNtf(const RawAddress& address,
1108 uint8_t features = 0x00) {
1109 HasDbBuilder builder = {
1110 .has = true,
1111 .features = true,
1112 .features_ntf = false,
1113 .preset_cp = false,
1114 .preset_cp_ntf = false,
1115 .preset_cp_ind = false,
1116 .active_preset_idx = false,
1117 .active_preset_idx_ntf = false,
1118 };
1119 set_sample_database(address, builder, features);
1120 }
1121
SetSampleDatabaseHasPresetsNtf(const RawAddress & address,uint8_t features=bluetooth::has::kFeatureBitHearingAidTypeMonaural,std::optional<std::set<HasPreset,HasPreset::ComparatorDesc>> presets=std::nullopt)1122 void SetSampleDatabaseHasPresetsNtf(
1123 const RawAddress& address,
1124 uint8_t features = bluetooth::has::kFeatureBitHearingAidTypeMonaural,
1125 std::optional<std::set<HasPreset, HasPreset::ComparatorDesc>> presets =
1126 std::nullopt) {
1127 HasDbBuilder builder = {
1128 .has = true,
1129 .features = true,
1130 .features_ntf = true,
1131 .preset_cp = true,
1132 .preset_cp_ntf = true,
1133 .preset_cp_ind = true,
1134 .active_preset_idx = true,
1135 .active_preset_idx_ntf = true,
1136 };
1137
1138 set_sample_database(address, builder, features, presets);
1139 }
1140
SetSampleDatabaseHasNoPresetsFlagsOnly(const RawAddress & address)1141 void SetSampleDatabaseHasNoPresetsFlagsOnly(const RawAddress& address) {
1142 uint8_t features = bluetooth::has::kFeatureBitHearingAidTypeMonaural;
1143 HasDbBuilder builder = {
1144 .has = true,
1145 .features = true,
1146 .features_ntf = true,
1147 .preset_cp = false,
1148 .preset_cp_ntf = false,
1149 .preset_cp_ind = false,
1150 .active_preset_idx = false,
1151 .active_preset_idx_ntf = false,
1152 };
1153
1154 set_sample_database(address, builder, features, std::nullopt);
1155 }
1156
1157 std::unique_ptr<MockHasCallbacks> callbacks;
1158 bluetooth::manager::MockBtmInterface btm_interface;
1159 bluetooth::storage::MockBtifStorageInterface btif_storage_interface_;
1160 controller::MockControllerInterface controller_interface_;
1161 gatt::MockBtaGattInterface gatt_interface;
1162 gatt::MockBtaGattQueue gatt_queue;
1163 MockCsisClient mock_csis_client_module_;
1164 tBTA_GATTC_CBACK* gatt_callback;
1165 const uint8_t gatt_if = 0xfe;
1166 std::map<uint8_t, RawAddress> connected_devices;
1167 std::map<uint16_t, std::list<gatt::Service>> services_map;
1168 bool encryption_result;
1169 };
1170
1171 class HasClientTest : public HasClientTestBase {
SetUp(void)1172 void SetUp(void) override {
1173 HasClientTestBase::SetUp();
1174 TestAppRegister();
1175 }
TearDown(void)1176 void TearDown(void) override {
1177 TestAppUnregister();
1178 HasClientTestBase::TearDown();
1179 }
1180 };
1181
TEST_F(HasClientTestBase,test_get_uninitialized)1182 TEST_F(HasClientTestBase, test_get_uninitialized) {
1183 ASSERT_DEATH(HasClient::Get(), "");
1184 }
1185
TEST_F(HasClientTestBase,test_initialize)1186 TEST_F(HasClientTestBase, test_initialize) {
1187 HasClient::Initialize(callbacks.get(), base::DoNothing());
1188 ASSERT_TRUE(HasClient::IsHasClientRunning());
1189 HasClient::CleanUp();
1190 }
1191
TEST_F(HasClientTestBase,test_initialize_twice)1192 TEST_F(HasClientTestBase, test_initialize_twice) {
1193 HasClient::Initialize(callbacks.get(), base::DoNothing());
1194 HasClient* has_p = HasClient::Get();
1195 HasClient::Initialize(callbacks.get(), base::DoNothing());
1196 ASSERT_EQ(has_p, HasClient::Get());
1197 HasClient::CleanUp();
1198 }
1199
TEST_F(HasClientTestBase,test_cleanup_initialized)1200 TEST_F(HasClientTestBase, test_cleanup_initialized) {
1201 HasClient::Initialize(callbacks.get(), base::DoNothing());
1202 HasClient::CleanUp();
1203 ASSERT_FALSE(HasClient::IsHasClientRunning());
1204 }
1205
TEST_F(HasClientTestBase,test_cleanup_uninitialized)1206 TEST_F(HasClientTestBase, test_cleanup_uninitialized) {
1207 HasClient::CleanUp();
1208 ASSERT_FALSE(HasClient::IsHasClientRunning());
1209 }
1210
TEST_F(HasClientTestBase,test_app_registration)1211 TEST_F(HasClientTestBase, test_app_registration) {
1212 TestAppRegister();
1213 TestAppUnregister();
1214 }
1215
TEST_F(HasClientTest,test_connect)1216 TEST_F(HasClientTest, test_connect) { TestConnect(GetTestAddress(1)); }
1217
TEST_F(HasClientTest,test_add_from_storage)1218 TEST_F(HasClientTest, test_add_from_storage) {
1219 TestAddFromStorage(GetTestAddress(1), 0, true);
1220 TestAddFromStorage(GetTestAddress(2), 0, false);
1221 }
1222
TEST_F(HasClientTest,test_disconnect_non_connected)1223 TEST_F(HasClientTest, test_disconnect_non_connected) {
1224 const RawAddress test_address = GetTestAddress(1);
1225
1226 /* Override the default action to prevent us sendind the connected event */
1227 EXPECT_CALL(gatt_interface,
1228 Open(gatt_if, test_address, BTM_BLE_DIRECT_CONNECTION, _))
1229 .WillOnce(Return());
1230 HasClient::Get()->Connect(test_address);
1231 TestDisconnect(test_address, GATT_INVALID_CONN_ID);
1232 }
1233
TEST_F(HasClientTest,test_has_connected)1234 TEST_F(HasClientTest, test_has_connected) {
1235 const RawAddress test_address = GetTestAddress(1);
1236 /* Minimal possible HA device (only feature flags) */
1237 SetSampleDatabaseHasNoPresetChange(
1238 test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
1239
1240 EXPECT_CALL(
1241 *callbacks,
1242 OnDeviceAvailable(test_address,
1243 bluetooth::has::kFeatureBitHearingAidTypeBinaural));
1244 EXPECT_CALL(*callbacks,
1245 OnConnectionState(ConnectionState::CONNECTED, test_address));
1246 TestConnect(test_address);
1247 }
1248
TEST_F(HasClientTest,test_disconnect_connected)1249 TEST_F(HasClientTest, test_disconnect_connected) {
1250 const RawAddress test_address = GetTestAddress(1);
1251 /* Minimal possible HA device (only feature flags) */
1252 SetSampleDatabaseHasNoPresetChange(
1253 test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
1254
1255 EXPECT_CALL(*callbacks,
1256 OnConnectionState(ConnectionState::CONNECTED, test_address))
1257 .Times(1);
1258 TestConnect(test_address);
1259
1260 EXPECT_CALL(*callbacks,
1261 OnConnectionState(ConnectionState::DISCONNECTED, test_address))
1262 .Times(1);
1263 TestDisconnect(test_address, 1);
1264 }
1265
TEST_F(HasClientTest,test_disconnected_while_autoconnect)1266 TEST_F(HasClientTest, test_disconnected_while_autoconnect) {
1267 const RawAddress test_address = GetTestAddress(1);
1268 TestAddFromStorage(test_address,
1269 bluetooth::has::kFeatureBitHearingAidTypeBinaural, true);
1270 /* autoconnect - don't indicate disconnection */
1271 EXPECT_CALL(*callbacks,
1272 OnConnectionState(ConnectionState::DISCONNECTED, test_address))
1273 .Times(0);
1274 /* Verify that the device still can connect in te background */
1275 InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER, true);
1276 }
1277
TEST_F(HasClientTest,test_encryption_failed)1278 TEST_F(HasClientTest, test_encryption_failed) {
1279 const RawAddress test_address = GetTestAddress(1);
1280 SetSampleDatabaseHasNoPresetChange(
1281 test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
1282 EXPECT_CALL(*callbacks,
1283 OnConnectionState(ConnectionState::DISCONNECTED, test_address))
1284 .Times(1);
1285 EXPECT_CALL(*callbacks,
1286 OnConnectionState(ConnectionState::CONNECTED, test_address))
1287 .Times(0);
1288 SetEncryptionResult(test_address, false);
1289 TestConnect(test_address);
1290 }
1291
TEST_F(HasClientTest,test_reconnect_after_encryption_failed)1292 TEST_F(HasClientTest, test_reconnect_after_encryption_failed) {
1293 const RawAddress test_address = GetTestAddress(1);
1294 SetSampleDatabaseHasNoPresetChange(
1295 test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
1296 EXPECT_CALL(*callbacks,
1297 OnConnectionState(ConnectionState::DISCONNECTED, test_address))
1298 .Times(1);
1299 EXPECT_CALL(*callbacks,
1300 OnConnectionState(ConnectionState::CONNECTED, test_address))
1301 .Times(0);
1302 SetEncryptionResult(test_address, false);
1303 TestConnect(test_address);
1304
1305 EXPECT_CALL(*callbacks,
1306 OnConnectionState(ConnectionState::CONNECTED, test_address))
1307 .Times(1);
1308 SetEncryptionResult(test_address, true);
1309 InjectConnectedEvent(test_address, GetTestConnId(test_address));
1310 }
1311
TEST_F(HasClientTest,test_reconnect_after_encryption_failed_from_storage)1312 TEST_F(HasClientTest, test_reconnect_after_encryption_failed_from_storage) {
1313 const RawAddress test_address = GetTestAddress(1);
1314
1315 SetSampleDatabaseHasNoPresetChange(
1316 test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
1317 SetEncryptionResult(test_address, false);
1318 TestAddFromStorage(test_address, 0, true);
1319 /* autoconnect - don't indicate disconnection */
1320 EXPECT_CALL(*callbacks,
1321 OnConnectionState(ConnectionState::DISCONNECTED, test_address))
1322 .Times(0);
1323 Mock::VerifyAndClearExpectations(&btm_interface);
1324
1325 /* Fake no persistent storage data */
1326 ON_CALL(btif_storage_interface_, GetLeaudioHasPresets(_, _, _))
1327 .WillByDefault([]() { return false; });
1328
1329 EXPECT_CALL(*callbacks,
1330 OnConnectionState(ConnectionState::CONNECTED, test_address))
1331 .Times(1);
1332 SetEncryptionResult(test_address, true);
1333 InjectConnectedEvent(test_address, GetTestConnId(test_address));
1334 }
1335
TEST_F(HasClientTest,test_load_from_storage_and_connect)1336 TEST_F(HasClientTest, test_load_from_storage_and_connect) {
1337 const RawAddress test_address = GetTestAddress(1);
1338 SetSampleDatabaseHasPresetsNtf(test_address, kFeatureBitDynamicPresets, {{}});
1339 SetEncryptionResult(test_address, true);
1340
1341 std::set<HasPreset, HasPreset::ComparatorDesc> has_presets = {{
1342 HasPreset(5, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1343 "YourWritablePreset5"),
1344 HasPreset(55, HasPreset::kPropertyAvailable, "YourPreset55"),
1345 }};
1346
1347 /* Load persistent storage data */
1348 ON_CALL(btif_storage_interface_, GetLeaudioHasPresets(test_address, _, _))
1349 .WillByDefault([&has_presets](const RawAddress& address,
1350 std::vector<uint8_t>& presets_bin,
1351 uint8_t& active_preset) {
1352 /* Generate presets binary to be used instead the attribute values */
1353 HasDevice device(address, 0);
1354 device.has_presets = has_presets;
1355 active_preset = 55;
1356
1357 if (device.SerializePresets(presets_bin)) return true;
1358
1359 return false;
1360 });
1361
1362 EXPECT_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _))
1363 .Times(1 // preset control point
1364 + 1 // active preset
1365 + 1); // features
1366
1367 EXPECT_CALL(*callbacks,
1368 OnDeviceAvailable(test_address,
1369 (kFeatureBitWritablePresets |
1370 kFeatureBitPresetSynchronizationSupported |
1371 kFeatureBitHearingAidTypeBanded)));
1372
1373 std::vector<PresetInfo> loaded_preset_details;
1374 EXPECT_CALL(*callbacks,
1375 OnPresetInfo(std::variant<RawAddress, int>(test_address),
1376 PresetInfoReason::ALL_PRESET_INFO, _))
1377 .WillOnce(SaveArg<2>(&loaded_preset_details));
1378
1379 EXPECT_CALL(*callbacks, OnActivePresetSelected(
1380 std::variant<RawAddress, int>(test_address), 55));
1381
1382 EXPECT_CALL(*callbacks,
1383 OnConnectionState(ConnectionState::CONNECTED, test_address));
1384
1385 /* Expect no read or write operations when loading from storage */
1386 EXPECT_CALL(gatt_queue, ReadCharacteristic(1, _, _, _)).Times(0);
1387 EXPECT_CALL(gatt_queue, WriteDescriptor(1, _, _, _, _, _)).Times(3);
1388
1389 TestAddFromStorage(test_address,
1390 kFeatureBitWritablePresets |
1391 kFeatureBitPresetSynchronizationSupported |
1392 kFeatureBitHearingAidTypeBanded,
1393 true);
1394
1395 for (auto const& info : loaded_preset_details) {
1396 auto preset = has_presets.find(info.preset_index);
1397 ASSERT_NE(preset, has_presets.end());
1398 if (preset->GetProperties() & HasPreset::kPropertyAvailable)
1399 ASSERT_TRUE(info.available);
1400 if (preset->GetProperties() & HasPreset::kPropertyWritable)
1401 ASSERT_TRUE(info.writable);
1402 ASSERT_EQ(preset->GetName(), info.preset_name);
1403 }
1404 }
1405
TEST_F(HasClientTest,test_load_from_storage)1406 TEST_F(HasClientTest, test_load_from_storage) {
1407 const RawAddress test_address = GetTestAddress(1);
1408 SetSampleDatabaseHasPresetsNtf(test_address, kFeatureBitDynamicPresets, {{}});
1409 SetEncryptionResult(test_address, true);
1410
1411 std::set<HasPreset, HasPreset::ComparatorDesc> has_presets = {{
1412 HasPreset(5, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1413 "YourWritablePreset5"),
1414 HasPreset(55, HasPreset::kPropertyAvailable, "YourPreset55"),
1415 }};
1416
1417 /* Load persistent storage data */
1418 ON_CALL(btif_storage_interface_, GetLeaudioHasPresets(test_address, _, _))
1419 .WillByDefault([&has_presets](const RawAddress& address,
1420 std::vector<uint8_t>& presets_bin,
1421 uint8_t& active_preset) {
1422 /* Generate presets binary to be used instead the attribute values */
1423 HasDevice device(address, 0);
1424 device.has_presets = has_presets;
1425 active_preset = 55;
1426
1427 if (device.SerializePresets(presets_bin)) return true;
1428
1429 return false;
1430 });
1431
1432 EXPECT_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _))
1433 .Times(0); // features
1434
1435 EXPECT_CALL(*callbacks,
1436 OnDeviceAvailable(test_address,
1437 (kFeatureBitWritablePresets |
1438 kFeatureBitPresetSynchronizationSupported |
1439 kFeatureBitHearingAidTypeBanded)));
1440
1441 std::vector<PresetInfo> loaded_preset_details;
1442 EXPECT_CALL(*callbacks,
1443 OnPresetInfo(std::variant<RawAddress, int>(test_address),
1444 PresetInfoReason::ALL_PRESET_INFO, _))
1445 .Times(0);
1446
1447 /* Expect no read or write operations when loading from storage */
1448 EXPECT_CALL(gatt_queue, ReadCharacteristic(1, _, _, _)).Times(0);
1449 EXPECT_CALL(gatt_queue, WriteDescriptor(1, _, _, _, _, _)).Times(0);
1450
1451 TestAddFromStorage(test_address,
1452 kFeatureBitWritablePresets |
1453 kFeatureBitPresetSynchronizationSupported |
1454 kFeatureBitHearingAidTypeBanded,
1455 false);
1456 }
1457
TEST_F(HasClientTest,test_write_to_storage)1458 TEST_F(HasClientTest, test_write_to_storage) {
1459 const RawAddress test_address = GetTestAddress(1);
1460
1461 std::set<HasPreset, HasPreset::ComparatorDesc> has_presets = {{
1462 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
1463 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1464 "Preset2"),
1465 }};
1466 SetSampleDatabaseHasPresetsNtf(
1467 test_address,
1468 bluetooth::has::kFeatureBitHearingAidTypeBanded |
1469 bluetooth::has::kFeatureBitWritablePresets |
1470 bluetooth::has::kFeatureBitDynamicPresets,
1471 has_presets);
1472
1473 std::vector<uint8_t> serialized;
1474 EXPECT_CALL(
1475 btif_storage_interface_,
1476 AddLeaudioHasDevice(test_address, _,
1477 bluetooth::has::kFeatureBitHearingAidTypeBanded |
1478 bluetooth::has::kFeatureBitWritablePresets |
1479 bluetooth::has::kFeatureBitDynamicPresets,
1480 1))
1481 .WillOnce(SaveArg<1>(&serialized));
1482 TestConnect(test_address);
1483
1484 /* Deserialize the written binary to verify the content */
1485 HasDevice clone(test_address,
1486 bluetooth::has::kFeatureBitHearingAidTypeBanded |
1487 bluetooth::has::kFeatureBitWritablePresets |
1488 bluetooth::has::kFeatureBitDynamicPresets);
1489 ASSERT_TRUE(HasDevice::DeserializePresets(serialized.data(),
1490 serialized.size(), clone));
1491 auto storage_info = clone.GetAllPresetInfo();
1492 ASSERT_EQ(storage_info.size(), has_presets.size());
1493 for (auto const& info : storage_info) {
1494 auto preset = has_presets.find(info.preset_index);
1495 ASSERT_NE(preset, has_presets.end());
1496 if (preset->GetProperties() & HasPreset::kPropertyAvailable)
1497 ASSERT_TRUE(info.available);
1498 if (preset->GetProperties() & HasPreset::kPropertyWritable)
1499 ASSERT_TRUE(info.writable);
1500 ASSERT_EQ(preset->GetName(), info.preset_name);
1501 }
1502 }
1503
TEST_F(HasClientTest,test_discovery_basic_has_no_opt_ntf)1504 TEST_F(HasClientTest, test_discovery_basic_has_no_opt_ntf) {
1505 const RawAddress test_address = GetTestAddress(1);
1506 auto test_conn_id = GetTestConnId(test_address);
1507
1508 SetSampleDatabaseHasNoOptionalNtf(test_address);
1509
1510 std::variant<RawAddress, int> addr_or_group = test_address;
1511 std::vector<PresetInfo> preset_details;
1512 uint8_t active_preset_index;
1513 uint8_t has_features;
1514
1515 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _))
1516 .WillOnce(SaveArg<1>(&has_features));
1517 EXPECT_CALL(*callbacks,
1518 OnConnectionState(ConnectionState::CONNECTED, test_address));
1519 EXPECT_CALL(*callbacks, OnPresetInfo(_, PresetInfoReason::ALL_PRESET_INFO, _))
1520 .WillOnce(DoAll(SaveArg<0>(&addr_or_group), SaveArg<2>(&preset_details)));
1521 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
1522 .WillOnce(
1523 DoAll(SaveArg<0>(&addr_or_group), SaveArg<1>(&active_preset_index)));
1524 TestConnect(test_address);
1525
1526 /* Verify sample database content */
1527 ASSERT_TRUE(std::holds_alternative<RawAddress>(addr_or_group));
1528 ASSERT_EQ(std::get<RawAddress>(addr_or_group), test_address);
1529 ASSERT_EQ(has_features, 0x00);
1530 ASSERT_EQ(active_preset_index,
1531 current_peer_presets_.at(test_conn_id).begin()->GetIndex());
1532
1533 /* Verify presets */
1534 uint16_t conn_id = GetTestConnId(test_address);
1535 ASSERT_NE(preset_details.size(), 0u);
1536 ASSERT_EQ(current_peer_presets_.at(conn_id).size(), preset_details.size());
1537
1538 for (auto const& preset : current_peer_presets_.at(conn_id)) {
1539 auto it =
1540 std::find_if(preset_details.cbegin(), preset_details.cend(),
1541 [&preset](auto const& preset_info) {
1542 return preset_info.preset_index == preset.GetIndex();
1543 });
1544 ASSERT_NE(it, preset_details.cend());
1545 ASSERT_EQ(preset.GetName(), it->preset_name);
1546 ASSERT_EQ(preset.IsAvailable(), it->available);
1547 ASSERT_EQ(preset.IsWritable(), it->writable);
1548 }
1549
1550 /* Verify active preset is there */
1551 ASSERT_EQ(preset_details.size(),
1552 current_peer_presets_.at(test_conn_id).size());
1553 ASSERT_TRUE(std::find_if(preset_details.begin(), preset_details.end(),
1554 [active_preset_index](auto const& preset_info) {
1555 return preset_info.preset_index ==
1556 active_preset_index;
1557 }) != preset_details.end());
1558 }
1559
TEST_F(HasClientTest,test_discovery_has_not_found)1560 TEST_F(HasClientTest, test_discovery_has_not_found) {
1561 const RawAddress test_address = GetTestAddress(1);
1562 SetSampleDatabaseNoHas(test_address);
1563
1564 EXPECT_CALL(*callbacks,
1565 OnConnectionState(ConnectionState::CONNECTED, test_address))
1566 .Times(0);
1567 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _)).Times(0);
1568 EXPECT_CALL(*callbacks, OnFeaturesUpdate(test_address, _)).Times(0);
1569 EXPECT_CALL(*callbacks,
1570 OnConnectionState(ConnectionState::DISCONNECTED, test_address));
1571
1572 TestConnect(test_address);
1573 }
1574
TEST_F(HasClientTest,test_discovery_has_broken_no_active_preset)1575 TEST_F(HasClientTest, test_discovery_has_broken_no_active_preset) {
1576 const RawAddress test_address = GetTestAddress(1);
1577 SetSampleDatabaseHasBrokenNoActivePreset(test_address);
1578
1579 EXPECT_CALL(*callbacks,
1580 OnConnectionState(ConnectionState::CONNECTED, test_address))
1581 .Times(0);
1582 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _)).Times(0);
1583 EXPECT_CALL(*callbacks, OnFeaturesUpdate(test_address, _)).Times(0);
1584 EXPECT_CALL(*callbacks,
1585 OnConnectionState(ConnectionState::DISCONNECTED, test_address));
1586
1587 TestConnect(test_address);
1588 }
1589
TEST_F(HasClientTest,test_discovery_has_broken_no_active_preset_ntf)1590 TEST_F(HasClientTest, test_discovery_has_broken_no_active_preset_ntf) {
1591 const RawAddress test_address = GetTestAddress(1);
1592 SetSampleDatabaseHasBrokenNoActivePresetNtf(test_address);
1593
1594 EXPECT_CALL(*callbacks,
1595 OnConnectionState(ConnectionState::CONNECTED, test_address))
1596 .Times(0);
1597 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _)).Times(0);
1598 EXPECT_CALL(*callbacks, OnFeaturesUpdate(test_address, _)).Times(0);
1599 EXPECT_CALL(*callbacks,
1600 OnConnectionState(ConnectionState::DISCONNECTED, test_address));
1601
1602 TestConnect(test_address);
1603 }
1604
TEST_F(HasClientTest,test_discovery_has_features_ntf)1605 TEST_F(HasClientTest, test_discovery_has_features_ntf) {
1606 const RawAddress test_address = GetTestAddress(1);
1607 auto test_conn_id = GetTestConnId(test_address);
1608 uint8_t has_features;
1609
1610 SetSampleDatabaseHasOnlyFeaturesNtf(
1611 test_address, bluetooth::has::kFeatureBitHearingAidTypeBanded);
1612
1613 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _))
1614 .WillOnce(SaveArg<1>(&has_features));
1615 EXPECT_CALL(*callbacks,
1616 OnConnectionState(ConnectionState::CONNECTED, test_address))
1617 .Times(1);
1618
1619 /* Verify subscription to features */
1620 EXPECT_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _))
1621 .Times(AnyNumber());
1622 EXPECT_CALL(gatt_interface,
1623 RegisterForNotifications(gatt_if, test_address,
1624 HasDbBuilder::kFeaturesValHdl));
1625
1626 /* Verify features CCC was written */
1627 EXPECT_CALL(gatt_queue, WriteDescriptor(test_conn_id, _, _, _, _, _))
1628 .Times(AnyNumber());
1629 EXPECT_CALL(gatt_queue,
1630 WriteDescriptor(test_conn_id, HasDbBuilder::kFeaturesValHdl + 1,
1631 std::vector<uint8_t>{0x01, 0x00}, _, _, _));
1632 TestConnect(test_address);
1633
1634 /* Verify features */
1635 ASSERT_EQ(has_features, bluetooth::has::kFeatureBitHearingAidTypeBanded);
1636
1637 uint8_t new_features;
1638
1639 /* Verify peer features change notification */
1640 EXPECT_CALL(*callbacks, OnFeaturesUpdate(test_address, _))
1641 .WillOnce(SaveArg<1>(&new_features));
1642 InjectNotificationEvent(test_address, test_conn_id,
1643 HasDbBuilder::kFeaturesValHdl,
1644 std::vector<uint8_t>({0x00}));
1645 ASSERT_NE(has_features, new_features);
1646 }
1647
TEST_F(HasClientTest,test_discovery_has_features_no_ntf)1648 TEST_F(HasClientTest, test_discovery_has_features_no_ntf) {
1649 const RawAddress test_address = GetTestAddress(1);
1650 auto test_conn_id = GetTestConnId(test_address);
1651 uint8_t has_features;
1652
1653 SetSampleDatabaseHasOnlyFeaturesNoNtf(
1654 test_address, bluetooth::has::kFeatureBitHearingAidTypeBanded);
1655
1656 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _))
1657 .WillOnce(SaveArg<1>(&has_features));
1658 EXPECT_CALL(*callbacks,
1659 OnConnectionState(ConnectionState::CONNECTED, test_address))
1660 .Times(1);
1661
1662 /* Verify no subscription to features */
1663 EXPECT_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _))
1664 .Times(AnyNumber());
1665 EXPECT_CALL(gatt_interface,
1666 RegisterForNotifications(gatt_if, test_address,
1667 HasDbBuilder::kFeaturesValHdl))
1668 .Times(0);
1669
1670 /* Verify no features CCC was written */
1671 EXPECT_CALL(gatt_queue, WriteDescriptor(test_conn_id, _, _, _, _, _))
1672 .Times(AnyNumber());
1673 EXPECT_CALL(gatt_queue,
1674 WriteDescriptor(test_conn_id, HasDbBuilder::kFeaturesValHdl + 1,
1675 _, _, _, _))
1676 .Times(0);
1677 TestConnect(test_address);
1678
1679 /* Verify features */
1680 ASSERT_EQ(has_features, bluetooth::has::kFeatureBitHearingAidTypeBanded);
1681 }
1682
TEST_F(HasClientTest,test_discovery_has_multiple_presets_ntf)1683 TEST_F(HasClientTest, test_discovery_has_multiple_presets_ntf) {
1684 const RawAddress test_address = GetTestAddress(1);
1685 SetSampleDatabaseHasPresetsNtf(
1686 test_address, bluetooth::has::kFeatureBitHearingAidTypeBanded);
1687
1688 std::variant<RawAddress, int> addr_or_group = test_address;
1689 std::vector<PresetInfo> preset_details;
1690 uint8_t active_preset_index;
1691 uint8_t has_features;
1692
1693 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _))
1694 .WillOnce(SaveArg<1>(&has_features));
1695 EXPECT_CALL(*callbacks,
1696 OnConnectionState(ConnectionState::CONNECTED, test_address));
1697 EXPECT_CALL(*callbacks, OnPresetInfo(_, PresetInfoReason::ALL_PRESET_INFO, _))
1698 .WillOnce(DoAll(SaveArg<0>(&addr_or_group), SaveArg<2>(&preset_details)));
1699 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
1700 .WillOnce(
1701 DoAll(SaveArg<0>(&addr_or_group), SaveArg<1>(&active_preset_index)));
1702
1703 /* Verify subscription to control point */
1704 EXPECT_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _))
1705 .Times(AnyNumber());
1706 EXPECT_CALL(gatt_interface,
1707 RegisterForNotifications(gatt_if, test_address,
1708 HasDbBuilder::kPresetsCtpValHdl));
1709
1710 /* Verify features CCC was written */
1711 EXPECT_CALL(gatt_queue, WriteDescriptor(1, _, _, _, _, _)).Times(AnyNumber());
1712 EXPECT_CALL(gatt_queue,
1713 WriteDescriptor(1, HasDbBuilder::kPresetsCtpValHdl + 1,
1714 std::vector<uint8_t>{0x03, 0x00}, _, _, _));
1715 TestConnect(test_address);
1716
1717 /* Verify features */
1718 ASSERT_EQ(has_features, bluetooth::has::kFeatureBitHearingAidTypeBanded);
1719 }
1720
TEST_F(HasClientTest,test_active_preset_change)1721 TEST_F(HasClientTest, test_active_preset_change) {
1722 const RawAddress test_address = GetTestAddress(1);
1723 auto test_conn_id = GetTestConnId(test_address);
1724
1725 SetSampleDatabaseHasNoOptionalNtf(test_address);
1726
1727 uint8_t active_preset_index;
1728 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _));
1729 EXPECT_CALL(*callbacks,
1730 OnPresetInfo(_, PresetInfoReason::ALL_PRESET_INFO, _));
1731 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
1732 .WillOnce(SaveArg<1>(&active_preset_index));
1733 EXPECT_CALL(*callbacks,
1734 OnConnectionState(ConnectionState::CONNECTED, test_address));
1735 TestConnect(test_address);
1736
1737 uint8_t new_active_preset;
1738 EXPECT_CALL(*callbacks, OnActivePresetSelected(
1739 std::variant<RawAddress, int>(test_address), _))
1740 .WillOnce(SaveArg<1>(&new_active_preset));
1741 InjectNotificationEvent(test_address, test_conn_id,
1742 HasDbBuilder::kActivePresetIndexValHdl,
1743 std::vector<uint8_t>({0x00}));
1744
1745 ASSERT_NE(active_preset_index, new_active_preset);
1746 ASSERT_EQ(new_active_preset, 0x00);
1747 }
1748
TEST_F(HasClientTest,test_duplicate_presets)1749 TEST_F(HasClientTest, test_duplicate_presets) {
1750 const RawAddress test_address = GetTestAddress(1);
1751 std::vector<PresetInfo> preset_details;
1752
1753 /* Handle duplicates gracefully */
1754 SetSampleDatabaseHasPresetsNtf(
1755 test_address, kFeatureBitWritablePresets,
1756 {{HasPreset(5,
1757 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1758 "YourWritablePreset5"),
1759 HasPreset(5,
1760 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1761 "YourWritablePreset5")}});
1762
1763 EXPECT_CALL(*callbacks,
1764 OnConnectionState(ConnectionState::CONNECTED, test_address));
1765 EXPECT_CALL(*callbacks, OnPresetInfo(_, PresetInfoReason::ALL_PRESET_INFO, _))
1766 .WillOnce(SaveArg<2>(&preset_details));
1767 TestConnect(test_address);
1768
1769 /* Verify presets - expect 1, no duplicates */
1770 ASSERT_EQ(preset_details.size(), 1u);
1771 auto preset = std::find_if(
1772 preset_details.begin(), preset_details.end(),
1773 [](auto const& preset_info) { return preset_info.preset_index == 5; });
1774 ASSERT_TRUE(preset != preset_details.end());
1775 ASSERT_EQ("YourWritablePreset5", preset->preset_name);
1776 ASSERT_TRUE(preset->available);
1777 ASSERT_TRUE(preset->writable);
1778 }
1779
TEST_F(HasClientTest,test_preset_set_name_invalid_index)1780 TEST_F(HasClientTest, test_preset_set_name_invalid_index) {
1781 const RawAddress test_address = GetTestAddress(1);
1782 SetSampleDatabaseHasPresetsNtf(test_address);
1783 TestConnect(test_address);
1784
1785 EXPECT_CALL(*callbacks,
1786 OnSetPresetNameError(std::variant<RawAddress, int>(test_address),
1787 0x40, ErrorCode::INVALID_PRESET_INDEX))
1788 .Times(1);
1789 EXPECT_CALL(gatt_queue,
1790 WriteCharacteristic(1, HasDbBuilder::kPresetsCtpValHdl, _,
1791 GATT_WRITE, _, _))
1792 .Times(0);
1793
1794 HasClient::Get()->SetPresetName(test_address, 0x40, "new preset name");
1795 }
1796
TEST_F(HasClientTest,test_preset_set_name_non_writable)1797 TEST_F(HasClientTest, test_preset_set_name_non_writable) {
1798 const RawAddress test_address = GetTestAddress(1);
1799 uint16_t test_conn_id = GetTestConnId(test_address);
1800
1801 SetSampleDatabaseHasPresetsNtf(
1802 test_address, kFeatureBitWritablePresets,
1803 {{
1804 HasPreset(5, HasPreset::kPropertyAvailable, "YourPreset5"),
1805 HasPreset(
1806 55, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1807 "YourWritablePreset55"),
1808 }});
1809 TestConnect(test_address);
1810
1811 EXPECT_CALL(*callbacks,
1812 OnSetPresetNameError(_, _, ErrorCode::SET_NAME_NOT_ALLOWED))
1813 .Times(1);
1814 EXPECT_CALL(gatt_queue,
1815 WriteCharacteristic(1, HasDbBuilder::kPresetsCtpValHdl, _,
1816 GATT_WRITE, _, _))
1817 .Times(0);
1818
1819 HasClient::Get()->SetPresetName(
1820 test_address, current_peer_presets_.at(test_conn_id).begin()->GetIndex(),
1821 "new preset name");
1822 }
1823
TEST_F(HasClientTest,test_preset_set_name_to_long)1824 TEST_F(HasClientTest, test_preset_set_name_to_long) {
1825 const RawAddress test_address = GetTestAddress(1);
1826 uint16_t test_conn_id = GetTestConnId(test_address);
1827
1828 SetSampleDatabaseHasPresetsNtf(
1829 test_address, kFeatureBitWritablePresets,
1830 {{HasPreset(5,
1831 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1832 "YourWritablePreset")}});
1833 TestConnect(test_address);
1834
1835 EXPECT_CALL(*callbacks,
1836 OnSetPresetNameError(_, _, ErrorCode::INVALID_PRESET_NAME_LENGTH))
1837 .Times(1);
1838 EXPECT_CALL(gatt_queue,
1839 WriteCharacteristic(test_conn_id, HasDbBuilder::kPresetsCtpValHdl,
1840 _, GATT_WRITE, _, _))
1841 .Times(0);
1842
1843 HasClient::Get()->SetPresetName(test_address, 5,
1844 "this name is more than 40 characters long");
1845 }
1846
TEST_F(HasClientTest,test_preset_set_name)1847 TEST_F(HasClientTest, test_preset_set_name) {
1848 const RawAddress test_address = GetTestAddress(1);
1849 uint16_t test_conn_id = GetTestConnId(test_address);
1850
1851 SetSampleDatabaseHasPresetsNtf(
1852 test_address, kFeatureBitWritablePresets,
1853 {{HasPreset(5,
1854 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1855 "YourWritablePreset5")}});
1856
1857 TestConnect(test_address);
1858
1859 std::vector<uint8_t> value;
1860 EXPECT_CALL(*callbacks, OnSetPresetNameError(_, _, _)).Times(0);
1861 EXPECT_CALL(gatt_queue,
1862 WriteCharacteristic(test_conn_id, HasDbBuilder::kPresetsCtpValHdl,
1863 _, GATT_WRITE, _, _));
1864
1865 std::vector<PresetInfo> updated_preset_details;
1866 EXPECT_CALL(*callbacks,
1867 OnPresetInfo(std::variant<RawAddress, int>(test_address),
1868 PresetInfoReason::PRESET_INFO_UPDATE, _))
1869 .WillOnce(SaveArg<2>(&updated_preset_details));
1870 HasClient::Get()->SetPresetName(test_address, 5, "new preset name");
1871
1872 ASSERT_EQ(1u, updated_preset_details.size());
1873 ASSERT_EQ(updated_preset_details[0].preset_name, "new preset name");
1874 }
1875
TEST_F(HasClientTest,test_preset_group_set_name)1876 TEST_F(HasClientTest, test_preset_group_set_name) {
1877 /* None of these devices support preset syncing */
1878 const RawAddress test_address1 = GetTestAddress(1);
1879 SetSampleDatabaseHasPresetsNtf(
1880 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural |
1881 bluetooth::has::kFeatureBitWritablePresets);
1882
1883 const RawAddress test_address2 = GetTestAddress(2);
1884 SetSampleDatabaseHasPresetsNtf(
1885 test_address2, bluetooth::has::kFeatureBitHearingAidTypeBinaural |
1886 bluetooth::has::kFeatureBitWritablePresets);
1887
1888 TestConnect(test_address1);
1889 TestConnect(test_address2);
1890
1891 /* Mock the csis group with two devices */
1892 uint8_t not_synced_group = 13;
1893 ON_CALL(mock_csis_client_module_, GetDeviceList(not_synced_group))
1894 .WillByDefault(
1895 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
1896 ON_CALL(mock_csis_client_module_,
1897 GetGroupId(test_address1, ::le_audio::uuid::kCapServiceUuid))
1898 .WillByDefault(Return(not_synced_group));
1899 ON_CALL(mock_csis_client_module_,
1900 GetGroupId(test_address2, ::le_audio::uuid::kCapServiceUuid))
1901 .WillByDefault(Return(not_synced_group));
1902
1903 std::vector<PresetInfo> preset_details;
1904 EXPECT_CALL(*callbacks, OnActivePresetSelected(
1905 std::variant<RawAddress, int>(test_address1), 55))
1906 .Times(0);
1907 EXPECT_CALL(*callbacks, OnActivePresetSelected(
1908 std::variant<RawAddress, int>(test_address2), 55))
1909 .Times(0);
1910
1911 /* This should be a group callback */
1912 EXPECT_CALL(*callbacks,
1913 OnPresetInfo(std::variant<RawAddress, int>(not_synced_group),
1914 PresetInfoReason::PRESET_INFO_UPDATE, _))
1915 .Times(1)
1916 .WillOnce(SaveArg<2>(&preset_details));
1917
1918 /* No locally synced opcodes support so expect both devices getting writes */
1919 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address1),
1920 HasDbBuilder::kPresetsCtpValHdl,
1921 _, GATT_WRITE, _, _))
1922 .Times(1);
1923 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address2),
1924 HasDbBuilder::kPresetsCtpValHdl,
1925 _, GATT_WRITE, _, _))
1926 .Times(1);
1927
1928 HasClient::Get()->SetPresetName(not_synced_group, 55, "new preset name");
1929 ASSERT_EQ(preset_details.size(), 1u);
1930 ASSERT_EQ(preset_details[0].preset_name, "new preset name");
1931 ASSERT_EQ(preset_details[0].preset_index, 55);
1932 }
1933
TEST_F(HasClientTest,test_multiple_presets_get_name)1934 TEST_F(HasClientTest, test_multiple_presets_get_name) {
1935 const RawAddress test_address = GetTestAddress(1);
1936 SetSampleDatabaseHasPresetsNtf(
1937 test_address, kFeatureBitWritablePresets,
1938 {{
1939 HasPreset(
1940 5, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1941 "YourWritablePreset5"),
1942 HasPreset(55, HasPreset::kPropertyAvailable, "YourPreset55"),
1943 HasPreset(99, 0, "YourPreset99"),
1944 }});
1945
1946 std::vector<PresetInfo> preset_details;
1947
1948 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _));
1949 EXPECT_CALL(*callbacks,
1950 OnConnectionState(ConnectionState::CONNECTED, test_address));
1951 EXPECT_CALL(*callbacks, OnPresetInfo(_, PresetInfoReason::ALL_PRESET_INFO, _))
1952 .WillOnce(SaveArg<2>(&preset_details));
1953 TestConnect(test_address);
1954
1955 /* Get each preset info individually */
1956 for (auto const& preset : preset_details) {
1957 std::vector<PresetInfo> new_preset_details;
1958
1959 EXPECT_CALL(*callbacks,
1960 OnPresetInfo(std::variant<RawAddress, int>(test_address),
1961 PresetInfoReason::PRESET_INFO_REQUEST_RESPONSE, _))
1962 .Times(1)
1963 .WillOnce(SaveArg<2>(&new_preset_details));
1964 HasClient::Get()->GetPresetInfo(test_address, preset.preset_index);
1965
1966 Mock::VerifyAndClearExpectations(&*callbacks);
1967 ASSERT_EQ(1u, new_preset_details.size());
1968 ASSERT_EQ(preset.preset_index, new_preset_details[0].preset_index);
1969 ASSERT_EQ(preset.preset_name, new_preset_details[0].preset_name);
1970 ASSERT_EQ(preset.writable, new_preset_details[0].writable);
1971 ASSERT_EQ(preset.available, new_preset_details[0].available);
1972 }
1973 }
1974
TEST_F(HasClientTest,test_presets_get_name_invalid_index)1975 TEST_F(HasClientTest, test_presets_get_name_invalid_index) {
1976 const RawAddress test_address = GetTestAddress(1);
1977 SetSampleDatabaseHasPresetsNtf(test_address);
1978 TestConnect(test_address);
1979
1980 EXPECT_CALL(*callbacks,
1981 OnPresetInfoError(std::variant<RawAddress, int>(test_address),
1982 128, ErrorCode::INVALID_PRESET_INDEX));
1983 HasClient::Get()->GetPresetInfo(test_address, 128);
1984
1985 EXPECT_CALL(*callbacks,
1986 OnPresetInfoError(std::variant<RawAddress, int>(test_address), 0,
1987 ErrorCode::INVALID_PRESET_INDEX));
1988 HasClient::Get()->GetPresetInfo(test_address, 0);
1989 }
1990
TEST_F(HasClientTest,test_presets_changed_generic_update_no_add_or_delete)1991 TEST_F(HasClientTest, test_presets_changed_generic_update_no_add_or_delete) {
1992 const RawAddress test_address = GetTestAddress(1);
1993 uint16_t test_conn_id = GetTestConnId(test_address);
1994
1995 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
1996 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
1997 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1998 "Preset2"),
1999 HasPreset(4, HasPreset::kPropertyAvailable, "Preset4"),
2000 HasPreset(7, HasPreset::kPropertyAvailable, "Preset7"),
2001 }};
2002 SetSampleDatabaseHasPresetsNtf(
2003 test_address,
2004 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2005 bluetooth::has::kFeatureBitDynamicPresets |
2006 bluetooth::has::kFeatureBitWritablePresets,
2007 presets);
2008
2009 EXPECT_CALL(*callbacks,
2010 OnConnectionState(ConnectionState::CONNECTED, test_address));
2011 TestConnect(test_address);
2012
2013 std::vector<PresetInfo> preset_details;
2014 EXPECT_CALL(*callbacks,
2015 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2016 PresetInfoReason::PRESET_INFO_UPDATE, _))
2017 .Times(1)
2018 .WillOnce(SaveArg<2>(&preset_details));
2019
2020 /* Inject generic update on the first preset */
2021 auto preset_index = 2;
2022 auto new_test_preset = HasPreset(preset_index, 0, "props new name");
2023 ASSERT_NE(*current_peer_presets_.at(test_conn_id).find(preset_index),
2024 new_test_preset);
2025
2026 InjectPresetChanged(test_conn_id, test_address, false, new_test_preset,
2027 1 /* prev_index */,
2028 ::le_audio::has::PresetCtpChangeId::PRESET_GENERIC_UPDATE,
2029 true /* is_last */);
2030
2031 /* Verify received preset info update on the 2nd preset */
2032 ASSERT_EQ(1u, preset_details.size());
2033 ASSERT_EQ(new_test_preset.GetIndex(), preset_details[0].preset_index);
2034 ASSERT_EQ(new_test_preset.IsAvailable(), preset_details[0].available);
2035 ASSERT_EQ(new_test_preset.IsWritable(), preset_details[0].writable);
2036 ASSERT_EQ(new_test_preset.GetName(), preset_details[0].preset_name);
2037 }
2038
TEST_F(HasClientTest,test_presets_changed_generic_update_add_and_delete)2039 TEST_F(HasClientTest, test_presets_changed_generic_update_add_and_delete) {
2040 const RawAddress test_address = GetTestAddress(1);
2041 uint16_t test_conn_id = GetTestConnId(test_address);
2042
2043 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2044 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2045 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2046 "Preset2"),
2047 HasPreset(4, HasPreset::kPropertyAvailable, "Preset4"),
2048 HasPreset(5, HasPreset::kPropertyAvailable, "Preset5"),
2049 HasPreset(32, HasPreset::kPropertyAvailable, "Preset32"),
2050 }};
2051 SetSampleDatabaseHasPresetsNtf(
2052 test_address,
2053 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2054 bluetooth::has::kFeatureBitWritablePresets,
2055 presets);
2056
2057 std::vector<PresetInfo> preset_details;
2058 EXPECT_CALL(*callbacks,
2059 OnConnectionState(ConnectionState::CONNECTED, test_address));
2060 EXPECT_CALL(*callbacks,
2061 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2062 PresetInfoReason::ALL_PRESET_INFO, _))
2063 .Times(1)
2064 .WillOnce(SaveArg<2>(&preset_details));
2065 TestConnect(test_address);
2066
2067 /* Expect more OnPresetInfo call */
2068 std::vector<PresetInfo> updated_preset_details;
2069 EXPECT_CALL(*callbacks,
2070 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2071 PresetInfoReason::PRESET_INFO_UPDATE, _))
2072 .Times(1)
2073 .WillOnce(SaveArg<2>(&updated_preset_details));
2074
2075 /* Expect more OnPresetInfo call */
2076 std::vector<PresetInfo> deleted_preset_details;
2077 EXPECT_CALL(*callbacks,
2078 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2079 PresetInfoReason::PRESET_DELETED, _))
2080 .Times(1)
2081 .WillOnce(SaveArg<2>(&deleted_preset_details));
2082
2083 /* Inject generic updates */
2084 /* First event replaces all the existing presets from 1 to 8 with preset 8
2085 */
2086 auto new_test_preset1 =
2087 HasPreset(8, HasPreset::kPropertyAvailable, "props new name9");
2088 InjectPresetChanged(test_conn_id, test_address, false, new_test_preset1,
2089 1 /* prev_index */,
2090 ::le_audio::has::PresetCtpChangeId::PRESET_GENERIC_UPDATE,
2091 false /* is_last */);
2092
2093 /* Second event adds preset 9 to the already existing presets 1 and 8 */
2094 auto new_test_preset2 =
2095 HasPreset(9, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2096 "props new name11");
2097 InjectPresetChanged(test_conn_id, test_address, false, new_test_preset2,
2098 8 /* prev_index */,
2099 ::le_audio::has::PresetCtpChangeId::PRESET_GENERIC_UPDATE,
2100 true /* is_last */);
2101
2102 /* Verify received preset info - expect presets 1, 32 unchanged, 8, 9
2103 * updated, and 2, 4, 5 deleted.
2104 */
2105 ASSERT_EQ(2u, updated_preset_details.size());
2106 ASSERT_EQ(new_test_preset1.GetIndex(),
2107 updated_preset_details[0].preset_index);
2108 ASSERT_EQ(new_test_preset1.IsAvailable(),
2109 updated_preset_details[0].available);
2110 ASSERT_EQ(new_test_preset1.IsWritable(), updated_preset_details[0].writable);
2111 ASSERT_EQ(new_test_preset1.GetName(), updated_preset_details[0].preset_name);
2112 ASSERT_EQ(new_test_preset2.GetIndex(),
2113 updated_preset_details[1].preset_index);
2114 ASSERT_EQ(new_test_preset2.IsAvailable(),
2115 updated_preset_details[1].available);
2116 ASSERT_EQ(new_test_preset2.IsWritable(), updated_preset_details[1].writable);
2117 ASSERT_EQ(new_test_preset2.GetName(), updated_preset_details[1].preset_name);
2118
2119 ASSERT_EQ(3u, deleted_preset_details.size());
2120 ASSERT_EQ(2, deleted_preset_details[0].preset_index);
2121 ASSERT_EQ(4, deleted_preset_details[1].preset_index);
2122 ASSERT_EQ(5, deleted_preset_details[2].preset_index);
2123 }
2124
TEST_F(HasClientTest,test_presets_changed_deleted)2125 TEST_F(HasClientTest, test_presets_changed_deleted) {
2126 const RawAddress test_address = GetTestAddress(1);
2127 uint16_t test_conn_id = GetTestConnId(test_address);
2128
2129 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2130 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2131 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2132 "Preset2"),
2133 }};
2134 SetSampleDatabaseHasPresetsNtf(
2135 test_address,
2136 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2137 bluetooth::has::kFeatureBitWritablePresets |
2138 bluetooth::has::kFeatureBitDynamicPresets,
2139 presets);
2140
2141 std::vector<PresetInfo> preset_details;
2142 EXPECT_CALL(*callbacks,
2143 OnConnectionState(ConnectionState::CONNECTED, test_address));
2144 EXPECT_CALL(*callbacks,
2145 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2146 PresetInfoReason::ALL_PRESET_INFO, _))
2147 .Times(1)
2148 .WillOnce(SaveArg<2>(&preset_details));
2149 TestConnect(test_address);
2150
2151 /* Expect second OnPresetInfo call */
2152 std::vector<PresetInfo> deleted_preset_details;
2153 EXPECT_CALL(*callbacks,
2154 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2155 PresetInfoReason::PRESET_DELETED, _))
2156 .Times(1)
2157 .WillOnce(SaveArg<2>(&deleted_preset_details));
2158
2159 /* Inject preset deletion of index 2 */
2160 auto deleted_index = preset_details[1].preset_index;
2161 InjectPresetChanged(test_conn_id, test_address, false,
2162 *presets.find(deleted_index), 0 /* prev_index */,
2163 ::le_audio::has::PresetCtpChangeId::PRESET_DELETED,
2164 true /* is_last */);
2165
2166 ASSERT_EQ(2u, preset_details.size());
2167 ASSERT_EQ(1u, deleted_preset_details.size());
2168 ASSERT_EQ(preset_details[1].preset_index,
2169 deleted_preset_details[0].preset_index);
2170 ASSERT_EQ(preset_details[1].writable, deleted_preset_details[0].writable);
2171 ASSERT_EQ(preset_details[1].available, deleted_preset_details[0].available);
2172 ASSERT_EQ(preset_details[1].preset_name,
2173 deleted_preset_details[0].preset_name);
2174 }
2175
TEST_F(HasClientTest,test_presets_changed_available)2176 TEST_F(HasClientTest, test_presets_changed_available) {
2177 const RawAddress test_address = GetTestAddress(1);
2178 uint16_t test_conn_id = GetTestConnId(test_address);
2179
2180 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2181 HasPreset(1, 0, "Universal"),
2182 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2183 "Preset2"),
2184 }};
2185 SetSampleDatabaseHasPresetsNtf(
2186 test_address,
2187 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2188 bluetooth::has::kFeatureBitWritablePresets |
2189 bluetooth::has::kFeatureBitDynamicPresets,
2190 presets);
2191
2192 std::vector<PresetInfo> preset_details;
2193 EXPECT_CALL(*callbacks,
2194 OnConnectionState(ConnectionState::CONNECTED, test_address));
2195 EXPECT_CALL(*callbacks,
2196 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2197 PresetInfoReason::ALL_PRESET_INFO, _))
2198 .Times(1)
2199 .WillOnce(SaveArg<2>(&preset_details));
2200 TestConnect(test_address);
2201
2202 /* Expect second OnPresetInfo call */
2203 std::vector<PresetInfo> changed_preset_details;
2204 EXPECT_CALL(*callbacks,
2205 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2206 PresetInfoReason::PRESET_AVAILABILITY_CHANGED, _))
2207 .Times(1)
2208 .WillOnce(SaveArg<2>(&changed_preset_details));
2209
2210 /* Inject preset deletion of index 2 */
2211 auto changed_index = preset_details[0].preset_index;
2212 InjectPresetChanged(test_conn_id, test_address, false,
2213 *presets.find(changed_index), 0 /* prev_index */,
2214 ::le_audio::has::PresetCtpChangeId::PRESET_AVAILABLE,
2215 true /* is_last */);
2216
2217 ASSERT_EQ(2u, preset_details.size());
2218 ASSERT_EQ(1u, changed_preset_details.size());
2219 ASSERT_EQ(preset_details[0].preset_index,
2220 changed_preset_details[0].preset_index);
2221 ASSERT_EQ(preset_details[0].writable, changed_preset_details[0].writable);
2222 ASSERT_EQ(preset_details[0].preset_name,
2223 changed_preset_details[0].preset_name);
2224 /* This field should have changed */
2225 ASSERT_NE(preset_details[0].available, changed_preset_details[0].available);
2226 ASSERT_TRUE(changed_preset_details[0].available);
2227 }
2228
TEST_F(HasClientTest,test_presets_changed_unavailable)2229 TEST_F(HasClientTest, test_presets_changed_unavailable) {
2230 const RawAddress test_address = GetTestAddress(1);
2231 uint16_t test_conn_id = GetTestConnId(test_address);
2232
2233 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2234 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2235 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2236 "Preset2"),
2237 }};
2238 SetSampleDatabaseHasPresetsNtf(
2239 test_address,
2240 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2241 bluetooth::has::kFeatureBitWritablePresets |
2242 bluetooth::has::kFeatureBitDynamicPresets,
2243 presets);
2244
2245 std::vector<PresetInfo> preset_details;
2246 EXPECT_CALL(*callbacks,
2247 OnConnectionState(ConnectionState::CONNECTED, test_address));
2248 EXPECT_CALL(*callbacks,
2249 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2250 PresetInfoReason::ALL_PRESET_INFO, _))
2251 .Times(1)
2252 .WillOnce(SaveArg<2>(&preset_details));
2253 TestConnect(test_address);
2254
2255 /* Expect second OnPresetInfo call */
2256 std::vector<PresetInfo> changed_preset_details;
2257 EXPECT_CALL(*callbacks,
2258 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2259 PresetInfoReason::PRESET_AVAILABILITY_CHANGED, _))
2260 .Times(1)
2261 .WillOnce(SaveArg<2>(&changed_preset_details));
2262
2263 /* Inject preset deletion of index 2 */
2264 auto changed_index = preset_details[0].preset_index;
2265 InjectPresetChanged(test_conn_id, test_address, false,
2266 *presets.find(changed_index), 0 /* prev_index */,
2267 ::le_audio::has::PresetCtpChangeId::PRESET_UNAVAILABLE,
2268 true /* is_last */);
2269
2270 ASSERT_EQ(2u, preset_details.size());
2271 ASSERT_EQ(1u, changed_preset_details.size());
2272 ASSERT_EQ(preset_details[0].preset_index,
2273 changed_preset_details[0].preset_index);
2274 ASSERT_EQ(preset_details[0].writable, changed_preset_details[0].writable);
2275 ASSERT_EQ(preset_details[0].preset_name,
2276 changed_preset_details[0].preset_name);
2277 /* This field should have changed */
2278 ASSERT_NE(preset_details[0].available, changed_preset_details[0].available);
2279 ASSERT_FALSE(changed_preset_details[0].available);
2280 }
2281
TEST_F(HasClientTest,test_select_preset_valid)2282 TEST_F(HasClientTest, test_select_preset_valid) {
2283 const RawAddress test_address = GetTestAddress(1);
2284 SetSampleDatabaseHasPresetsNtf(test_address);
2285
2286 uint8_t active_preset_index = 0;
2287 std::vector<PresetInfo> preset_details;
2288
2289 EXPECT_CALL(*callbacks,
2290 OnConnectionState(ConnectionState::CONNECTED, test_address));
2291 EXPECT_CALL(*callbacks,
2292 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2293 PresetInfoReason::ALL_PRESET_INFO, _))
2294 .Times(1)
2295 .WillOnce(SaveArg<2>(&preset_details));
2296 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
2297 .WillOnce(SaveArg<1>(&active_preset_index));
2298 TestConnect(test_address);
2299
2300 ASSERT_TRUE(preset_details.size() > 1);
2301 ASSERT_EQ(preset_details.front().preset_index, active_preset_index);
2302
2303 uint8_t new_active_preset_index = 0;
2304 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
2305 .WillOnce(SaveArg<1>(&new_active_preset_index));
2306
2307 HasClient::Get()->SelectActivePreset(test_address,
2308 preset_details.back().preset_index);
2309 Mock::VerifyAndClearExpectations(&*callbacks);
2310
2311 ASSERT_NE(active_preset_index, new_active_preset_index);
2312 ASSERT_EQ(preset_details.back().preset_index, new_active_preset_index);
2313 }
2314
TEST_F(HasClientTest,test_select_group_preset_invalid_group)2315 TEST_F(HasClientTest, test_select_group_preset_invalid_group) {
2316 const RawAddress test_address1 = GetTestAddress(1);
2317 SetSampleDatabaseHasPresetsNtf(test_address1);
2318
2319 const RawAddress test_address2 = GetTestAddress(2);
2320 SetSampleDatabaseHasPresetsNtf(test_address2);
2321
2322 TestConnect(test_address1);
2323 TestConnect(test_address2);
2324
2325 /* Mock the csis group with no devices */
2326 uint8_t unlucky_group = 13;
2327 ON_CALL(mock_csis_client_module_, GetDeviceList(unlucky_group))
2328 .WillByDefault(Return(std::vector<RawAddress>()));
2329
2330 EXPECT_CALL(*callbacks, OnActivePresetSelectError(
2331 std::variant<RawAddress, int>(unlucky_group),
2332 ErrorCode::OPERATION_NOT_POSSIBLE))
2333 .Times(1);
2334
2335 HasClient::Get()->SelectActivePreset(unlucky_group, 6);
2336 }
2337
TEST_F(HasClientTest,test_select_group_preset_valid_no_preset_sync_supported)2338 TEST_F(HasClientTest, test_select_group_preset_valid_no_preset_sync_supported) {
2339 /* None of these devices support preset syncing */
2340 const RawAddress test_address1 = GetTestAddress(1);
2341 SetSampleDatabaseHasPresetsNtf(
2342 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2343
2344 const RawAddress test_address2 = GetTestAddress(2);
2345 SetSampleDatabaseHasPresetsNtf(
2346 test_address2, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2347
2348 TestConnect(test_address1);
2349 TestConnect(test_address2);
2350
2351 /* Mock the csis group with two devices */
2352 uint8_t not_synced_group = 13;
2353 ON_CALL(mock_csis_client_module_, GetDeviceList(not_synced_group))
2354 .WillByDefault(
2355 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
2356 ON_CALL(mock_csis_client_module_,
2357 GetGroupId(test_address1, ::le_audio::uuid::kCapServiceUuid))
2358 .WillByDefault(Return(not_synced_group));
2359 ON_CALL(mock_csis_client_module_,
2360 GetGroupId(test_address2, ::le_audio::uuid::kCapServiceUuid))
2361 .WillByDefault(Return(not_synced_group));
2362
2363 uint8_t group_active_preset_index = 0;
2364 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2365 std::variant<RawAddress, int>(test_address1), 55))
2366 .Times(0);
2367 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2368 std::variant<RawAddress, int>(test_address2), 55))
2369 .Times(0);
2370 EXPECT_CALL(*callbacks,
2371 OnActivePresetSelected(
2372 std::variant<RawAddress, int>(not_synced_group), _))
2373 .WillOnce(SaveArg<1>(&group_active_preset_index));
2374
2375 /* No locally synced opcodes support so expect both devices getting writes */
2376 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address1),
2377 HasDbBuilder::kPresetsCtpValHdl,
2378 _, GATT_WRITE, _, _))
2379 .Times(1);
2380 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address2),
2381 HasDbBuilder::kPresetsCtpValHdl,
2382 _, GATT_WRITE, _, _))
2383 .Times(1);
2384
2385 HasClient::Get()->SelectActivePreset(not_synced_group, 55);
2386 ASSERT_EQ(group_active_preset_index, 55);
2387 }
2388
TEST_F(HasClientTest,test_select_group_preset_valid_preset_sync_supported)2389 TEST_F(HasClientTest, test_select_group_preset_valid_preset_sync_supported) {
2390 /* Only one of these devices support preset syncing */
2391 const RawAddress test_address1 = GetTestAddress(1);
2392 uint16_t test_conn_id1 = GetTestConnId(test_address1);
2393 SetSampleDatabaseHasPresetsNtf(
2394 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2395
2396 const RawAddress test_address2 = GetTestAddress(2);
2397 uint16_t test_conn_id2 = GetTestConnId(test_address2);
2398 SetSampleDatabaseHasPresetsNtf(
2399 test_address2,
2400 bluetooth::has::kFeatureBitHearingAidTypeBinaural |
2401 bluetooth::has::kFeatureBitPresetSynchronizationSupported);
2402
2403 uint8_t active_preset_index1 = 0;
2404 uint8_t active_preset_index2 = 0;
2405
2406 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2407 std::variant<RawAddress, int>(test_address1), _))
2408 .WillOnce(SaveArg<1>(&active_preset_index1));
2409 TestConnect(test_address1);
2410
2411 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2412 std::variant<RawAddress, int>(test_address2), _))
2413 .WillOnce(SaveArg<1>(&active_preset_index2));
2414 TestConnect(test_address2);
2415
2416 /* Mock the csis group with two devices */
2417 uint8_t synced_group = 13;
2418 ON_CALL(mock_csis_client_module_, GetDeviceList(synced_group))
2419 .WillByDefault(
2420 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
2421 ON_CALL(mock_csis_client_module_,
2422 GetGroupId(test_address1, ::le_audio::uuid::kCapServiceUuid))
2423 .WillByDefault(Return(synced_group));
2424 ON_CALL(mock_csis_client_module_,
2425 GetGroupId(test_address2, ::le_audio::uuid::kCapServiceUuid))
2426 .WillByDefault(Return(synced_group));
2427
2428 EXPECT_CALL(*callbacks, OnActivePresetSelectError(
2429 _, ErrorCode::GROUP_OPERATION_NOT_SUPPORTED))
2430 .Times(0);
2431
2432 /* Expect callback from the group but not from the devices */
2433 uint8_t group_active_preset_index = 0;
2434 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2435 std::variant<RawAddress, int>(test_address1), _))
2436 .Times(0);
2437 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2438 std::variant<RawAddress, int>(test_address2), _))
2439 .Times(0);
2440 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2441 std::variant<RawAddress, int>(synced_group), _))
2442 .WillOnce(SaveArg<1>(&group_active_preset_index));
2443
2444 /* Expect Ctp write on on this device which forwards operation to the other */
2445 EXPECT_CALL(gatt_queue, WriteCharacteristic(test_conn_id1,
2446 HasDbBuilder::kPresetsCtpValHdl,
2447 _, GATT_WRITE, _, _))
2448 .Times(0);
2449 EXPECT_CALL(gatt_queue, WriteCharacteristic(test_conn_id2,
2450 HasDbBuilder::kPresetsCtpValHdl,
2451 _, GATT_WRITE, _, _))
2452 .Times(1);
2453
2454 HasClient::Get()->SelectActivePreset(synced_group, 55);
2455 ASSERT_EQ(group_active_preset_index, 55);
2456 }
2457
TEST_F(HasClientTest,test_select_preset_invalid)2458 TEST_F(HasClientTest, test_select_preset_invalid) {
2459 const RawAddress test_address = GetTestAddress(1);
2460 uint16_t test_conn_id = GetTestConnId(test_address);
2461
2462 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2463 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2464 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2465 "Preset2"),
2466 }};
2467 SetSampleDatabaseHasPresetsNtf(
2468 test_address,
2469 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2470 bluetooth::has::kFeatureBitWritablePresets |
2471 bluetooth::has::kFeatureBitDynamicPresets,
2472 presets);
2473
2474 uint8_t active_preset_index = 0;
2475 std::vector<PresetInfo> preset_details;
2476
2477 EXPECT_CALL(*callbacks,
2478 OnConnectionState(ConnectionState::CONNECTED, test_address));
2479 EXPECT_CALL(*callbacks,
2480 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2481 PresetInfoReason::ALL_PRESET_INFO, _))
2482 .Times(1)
2483 .WillOnce(SaveArg<2>(&preset_details));
2484 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
2485 .WillOnce(SaveArg<1>(&active_preset_index));
2486 TestConnect(test_address);
2487
2488 ASSERT_TRUE(preset_details.size() > 1);
2489 ASSERT_EQ(preset_details.front().preset_index, active_preset_index);
2490
2491 /* Inject preset deletion of index 2 */
2492 auto deleted_index = preset_details[1].preset_index;
2493 InjectPresetChanged(test_conn_id, test_address, false,
2494 *presets.find(deleted_index), 0 /* prev_index */,
2495 ::le_audio::has::PresetCtpChangeId::PRESET_DELETED,
2496 true /* is_last */);
2497
2498 EXPECT_CALL(*callbacks, OnActivePresetSelectError(
2499 std::variant<RawAddress, int>(test_address),
2500 ErrorCode::INVALID_PRESET_INDEX))
2501 .Times(1);
2502
2503 /* Check if preset was actually deleted - try setting it as an active one */
2504 HasClient::Get()->SelectActivePreset(test_address,
2505 preset_details[1].preset_index);
2506 }
2507
TEST_F(HasClientTest,test_select_preset_next)2508 TEST_F(HasClientTest, test_select_preset_next) {
2509 const RawAddress test_address = GetTestAddress(1);
2510
2511 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2512 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2513 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2514 "Preset2"),
2515 }};
2516 SetSampleDatabaseHasPresetsNtf(
2517 test_address,
2518 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2519 bluetooth::has::kFeatureBitWritablePresets |
2520 bluetooth::has::kFeatureBitDynamicPresets,
2521 presets);
2522
2523 uint8_t active_preset_index = 0;
2524 std::vector<PresetInfo> preset_details;
2525
2526 EXPECT_CALL(*callbacks,
2527 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2528 PresetInfoReason::ALL_PRESET_INFO, _))
2529 .Times(1)
2530 .WillOnce(SaveArg<2>(&preset_details));
2531 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
2532 .WillOnce(SaveArg<1>(&active_preset_index));
2533 TestConnect(test_address);
2534
2535 ASSERT_TRUE(preset_details.size() > 1);
2536 ASSERT_EQ(1, active_preset_index);
2537
2538 /* Verify active preset change */
2539 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2540 std::variant<RawAddress, int>(test_address), 2));
2541 HasClient::Get()->NextActivePreset(test_address);
2542 }
2543
TEST_F(HasClientTest,test_select_group_preset_next_no_preset_sync_supported)2544 TEST_F(HasClientTest, test_select_group_preset_next_no_preset_sync_supported) {
2545 /* None of these devices support preset syncing */
2546 const RawAddress test_address1 = GetTestAddress(1);
2547 SetSampleDatabaseHasPresetsNtf(
2548 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2549
2550 const RawAddress test_address2 = GetTestAddress(2);
2551 SetSampleDatabaseHasPresetsNtf(
2552 test_address2, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2553
2554 TestConnect(test_address1);
2555 TestConnect(test_address2);
2556
2557 /* Mock the csis group with two devices */
2558 uint8_t not_synced_group = 13;
2559 ON_CALL(mock_csis_client_module_, GetDeviceList(not_synced_group))
2560 .WillByDefault(
2561 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
2562 ON_CALL(mock_csis_client_module_,
2563 GetGroupId(test_address1, ::le_audio::uuid::kCapServiceUuid))
2564 .WillByDefault(Return(not_synced_group));
2565 ON_CALL(mock_csis_client_module_,
2566 GetGroupId(test_address2, ::le_audio::uuid::kCapServiceUuid))
2567 .WillByDefault(Return(not_synced_group));
2568
2569 uint8_t group_active_preset_index = 0;
2570 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2571 std::variant<RawAddress, int>(test_address1), 55))
2572 .Times(0);
2573 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2574 std::variant<RawAddress, int>(test_address2), 55))
2575 .Times(0);
2576 EXPECT_CALL(*callbacks,
2577 OnActivePresetSelected(
2578 std::variant<RawAddress, int>(not_synced_group), _))
2579 .WillOnce(SaveArg<1>(&group_active_preset_index));
2580
2581 /* No locally synced opcodes support so expect both devices getting writes */
2582 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address1),
2583 HasDbBuilder::kPresetsCtpValHdl,
2584 _, GATT_WRITE, _, _))
2585 .Times(1);
2586 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address2),
2587 HasDbBuilder::kPresetsCtpValHdl,
2588 _, GATT_WRITE, _, _))
2589 .Times(1);
2590
2591 HasClient::Get()->NextActivePreset(not_synced_group);
2592 ASSERT_EQ(group_active_preset_index, 55);
2593 }
2594
TEST_F(HasClientTest,test_select_group_preset_next_preset_sync_supported)2595 TEST_F(HasClientTest, test_select_group_preset_next_preset_sync_supported) {
2596 /* Only one of these devices support preset syncing */
2597 const RawAddress test_address1 = GetTestAddress(1);
2598 uint16_t test_conn_id1 = GetTestConnId(test_address1);
2599 SetSampleDatabaseHasPresetsNtf(
2600 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2601
2602 const RawAddress test_address2 = GetTestAddress(2);
2603 uint16_t test_conn_id2 = GetTestConnId(test_address2);
2604 SetSampleDatabaseHasPresetsNtf(
2605 test_address2,
2606 bluetooth::has::kFeatureBitHearingAidTypeBinaural |
2607 bluetooth::has::kFeatureBitPresetSynchronizationSupported);
2608
2609 uint8_t active_preset_index1 = 0;
2610 uint8_t active_preset_index2 = 0;
2611
2612 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2613 std::variant<RawAddress, int>(test_address1), _))
2614 .WillOnce(SaveArg<1>(&active_preset_index1));
2615 TestConnect(test_address1);
2616
2617 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2618 std::variant<RawAddress, int>(test_address2), _))
2619 .WillOnce(SaveArg<1>(&active_preset_index2));
2620 TestConnect(test_address2);
2621
2622 /* Mock the csis group with two devices */
2623 uint8_t synced_group = 13;
2624 ON_CALL(mock_csis_client_module_, GetDeviceList(synced_group))
2625 .WillByDefault(
2626 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
2627 ON_CALL(mock_csis_client_module_,
2628 GetGroupId(test_address1, ::le_audio::uuid::kCapServiceUuid))
2629 .WillByDefault(Return(synced_group));
2630 ON_CALL(mock_csis_client_module_,
2631 GetGroupId(test_address2, ::le_audio::uuid::kCapServiceUuid))
2632 .WillByDefault(Return(synced_group));
2633
2634 EXPECT_CALL(*callbacks, OnActivePresetSelectError(
2635 _, ErrorCode::GROUP_OPERATION_NOT_SUPPORTED))
2636 .Times(0);
2637
2638 /* Expect callback from the group but not from the devices */
2639 uint8_t group_active_preset_index = 0;
2640 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2641 std::variant<RawAddress, int>(test_address1), _))
2642 .Times(0);
2643 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2644 std::variant<RawAddress, int>(test_address2), _))
2645 .Times(0);
2646 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2647 std::variant<RawAddress, int>(synced_group), _))
2648 .WillOnce(SaveArg<1>(&group_active_preset_index));
2649
2650 /* Expect Ctp write on on this device which forwards operation to the other */
2651 EXPECT_CALL(gatt_queue, WriteCharacteristic(test_conn_id1,
2652 HasDbBuilder::kPresetsCtpValHdl,
2653 _, GATT_WRITE, _, _))
2654 .Times(0);
2655 EXPECT_CALL(gatt_queue, WriteCharacteristic(test_conn_id2,
2656 HasDbBuilder::kPresetsCtpValHdl,
2657 _, GATT_WRITE, _, _))
2658 .Times(1);
2659
2660 HasClient::Get()->NextActivePreset(synced_group);
2661 ASSERT_EQ(group_active_preset_index, 55);
2662 }
2663
TEST_F(HasClientTest,test_select_preset_prev)2664 TEST_F(HasClientTest, test_select_preset_prev) {
2665 const RawAddress test_address = GetTestAddress(1);
2666
2667 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2668 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2669 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2670 "Preset2"),
2671 }};
2672 SetSampleDatabaseHasPresetsNtf(
2673 test_address,
2674 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2675 bluetooth::has::kFeatureBitWritablePresets |
2676 bluetooth::has::kFeatureBitDynamicPresets,
2677 presets);
2678
2679 uint8_t active_preset_index = 0;
2680 std::vector<PresetInfo> preset_details;
2681
2682 EXPECT_CALL(*callbacks,
2683 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2684 PresetInfoReason::ALL_PRESET_INFO, _))
2685 .Times(1)
2686 .WillOnce(SaveArg<2>(&preset_details));
2687 ON_CALL(*callbacks, OnActivePresetSelected(_, _))
2688 .WillByDefault(SaveArg<1>(&active_preset_index));
2689 TestConnect(test_address);
2690
2691 HasClient::Get()->SelectActivePreset(test_address, 2);
2692 ASSERT_TRUE(preset_details.size() > 1);
2693 ASSERT_EQ(2, active_preset_index);
2694
2695 /* Verify active preset change */
2696 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2697 std::variant<RawAddress, int>(test_address), 1));
2698 HasClient::Get()->PreviousActivePreset(test_address);
2699 }
2700
TEST_F(HasClientTest,test_select_group_preset_prev_no_preset_sync_supported)2701 TEST_F(HasClientTest, test_select_group_preset_prev_no_preset_sync_supported) {
2702 /* None of these devices support preset syncing */
2703 const RawAddress test_address1 = GetTestAddress(1);
2704 SetSampleDatabaseHasPresetsNtf(
2705 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2706
2707 const RawAddress test_address2 = GetTestAddress(2);
2708 SetSampleDatabaseHasPresetsNtf(
2709 test_address2, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2710
2711 TestConnect(test_address1);
2712 TestConnect(test_address2);
2713
2714 /* Mock the csis group with two devices */
2715 uint8_t not_synced_group = 13;
2716 ON_CALL(mock_csis_client_module_, GetDeviceList(not_synced_group))
2717 .WillByDefault(
2718 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
2719 ON_CALL(mock_csis_client_module_,
2720 GetGroupId(test_address1, ::le_audio::uuid::kCapServiceUuid))
2721 .WillByDefault(Return(not_synced_group));
2722 ON_CALL(mock_csis_client_module_,
2723 GetGroupId(test_address2, ::le_audio::uuid::kCapServiceUuid))
2724 .WillByDefault(Return(not_synced_group));
2725
2726 uint8_t group_active_preset_index = 0;
2727 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2728 std::variant<RawAddress, int>(test_address1), 55))
2729 .Times(0);
2730 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2731 std::variant<RawAddress, int>(test_address2), 55))
2732 .Times(0);
2733 EXPECT_CALL(*callbacks,
2734 OnActivePresetSelected(
2735 std::variant<RawAddress, int>(not_synced_group), _))
2736 .WillOnce(SaveArg<1>(&group_active_preset_index));
2737
2738 /* No locally synced opcodes support so expect both devices getting writes */
2739 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address1),
2740 HasDbBuilder::kPresetsCtpValHdl,
2741 _, GATT_WRITE, _, _))
2742 .Times(1);
2743 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address2),
2744 HasDbBuilder::kPresetsCtpValHdl,
2745 _, GATT_WRITE, _, _))
2746 .Times(1);
2747
2748 HasClient::Get()->PreviousActivePreset(not_synced_group);
2749 ASSERT_EQ(group_active_preset_index, 55);
2750 }
2751
TEST_F(HasClientTest,test_select_group_preset_prev_preset_sync_supported)2752 TEST_F(HasClientTest, test_select_group_preset_prev_preset_sync_supported) {
2753 /* Only one of these devices support preset syncing */
2754 const RawAddress test_address1 = GetTestAddress(1);
2755 uint16_t test_conn_id1 = GetTestConnId(test_address1);
2756 SetSampleDatabaseHasPresetsNtf(
2757 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2758
2759 const RawAddress test_address2 = GetTestAddress(2);
2760 uint16_t test_conn_id2 = GetTestConnId(test_address2);
2761 SetSampleDatabaseHasPresetsNtf(
2762 test_address2,
2763 bluetooth::has::kFeatureBitHearingAidTypeBinaural |
2764 bluetooth::has::kFeatureBitPresetSynchronizationSupported);
2765
2766 uint8_t active_preset_index1 = 0;
2767 uint8_t active_preset_index2 = 0;
2768
2769 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2770 std::variant<RawAddress, int>(test_address1), _))
2771 .WillOnce(SaveArg<1>(&active_preset_index1));
2772 TestConnect(test_address1);
2773
2774 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2775 std::variant<RawAddress, int>(test_address2), _))
2776 .WillOnce(SaveArg<1>(&active_preset_index2));
2777 TestConnect(test_address2);
2778
2779 /* Mock the csis group with two devices */
2780 uint8_t synced_group = 13;
2781 ON_CALL(mock_csis_client_module_, GetDeviceList(synced_group))
2782 .WillByDefault(
2783 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
2784 ON_CALL(mock_csis_client_module_,
2785 GetGroupId(test_address1, ::le_audio::uuid::kCapServiceUuid))
2786 .WillByDefault(Return(synced_group));
2787 ON_CALL(mock_csis_client_module_,
2788 GetGroupId(test_address2, ::le_audio::uuid::kCapServiceUuid))
2789 .WillByDefault(Return(synced_group));
2790
2791 EXPECT_CALL(*callbacks, OnActivePresetSelectError(
2792 _, ErrorCode::GROUP_OPERATION_NOT_SUPPORTED))
2793 .Times(0);
2794
2795 /* Expect callback from the group but not from the devices */
2796 uint8_t group_active_preset_index = 0;
2797 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2798 std::variant<RawAddress, int>(test_address1), _))
2799 .Times(0);
2800 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2801 std::variant<RawAddress, int>(test_address2), _))
2802 .Times(0);
2803 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2804 std::variant<RawAddress, int>(synced_group), _))
2805 .WillOnce(SaveArg<1>(&group_active_preset_index));
2806
2807 /* Expect Ctp write on on this device which forwards operation to the other */
2808 EXPECT_CALL(gatt_queue, WriteCharacteristic(test_conn_id1,
2809 HasDbBuilder::kPresetsCtpValHdl,
2810 _, GATT_WRITE, _, _))
2811 .Times(0);
2812 EXPECT_CALL(gatt_queue, WriteCharacteristic(test_conn_id2,
2813 HasDbBuilder::kPresetsCtpValHdl,
2814 _, GATT_WRITE, _, _))
2815 .Times(1);
2816
2817 HasClient::Get()->PreviousActivePreset(synced_group);
2818 ASSERT_EQ(group_active_preset_index, 55);
2819 }
2820
TEST_F(HasClientTest,test_select_has_no_presets)2821 TEST_F(HasClientTest, test_select_has_no_presets) {
2822 const RawAddress test_address = GetTestAddress(1);
2823 SetSampleDatabaseHasNoPresetsFlagsOnly(test_address);
2824
2825 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _)).Times(1);
2826 EXPECT_CALL(*callbacks,
2827 OnConnectionState(ConnectionState::CONNECTED, test_address))
2828 .Times(1);
2829 TestConnect(test_address);
2830
2831 /* Test this not so useful service */
2832 EXPECT_CALL(*callbacks,
2833 OnActivePresetSelectError(_, ErrorCode::OPERATION_NOT_SUPPORTED))
2834 .Times(3);
2835
2836 HasClient::Get()->SelectActivePreset(test_address, 0x01);
2837 HasClient::Get()->NextActivePreset(test_address);
2838 HasClient::Get()->PreviousActivePreset(test_address);
2839 }
2840
GetSocketBufferSize(int sockfd)2841 static int GetSocketBufferSize(int sockfd) {
2842 int socket_buffer_size;
2843 socklen_t optlen = sizeof(socket_buffer_size);
2844 getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&socket_buffer_size,
2845 &optlen);
2846 return socket_buffer_size;
2847 }
2848
SimpleJsonValidator(int fd,int * dumpsys_byte_cnt)2849 bool SimpleJsonValidator(int fd, int* dumpsys_byte_cnt) {
2850 std::ostringstream ss;
2851
2852 char buf{0};
2853 bool within_double_quotes{false};
2854 int left_bracket{0}, right_bracket{0};
2855 int left_sq_bracket{0}, right_sq_bracket{0};
2856 while (read(fd, &buf, 1) != -1) {
2857 switch (buf) {
2858 (*dumpsys_byte_cnt)++;
2859 case '"':
2860 within_double_quotes = !within_double_quotes;
2861 break;
2862 case '{':
2863 if (!within_double_quotes) {
2864 left_bracket++;
2865 }
2866 break;
2867 case '}':
2868 if (!within_double_quotes) {
2869 right_bracket++;
2870 }
2871 break;
2872 case '[':
2873 if (!within_double_quotes) {
2874 left_sq_bracket++;
2875 }
2876 break;
2877 case ']':
2878 if (!within_double_quotes) {
2879 right_sq_bracket++;
2880 }
2881 break;
2882 default:
2883 break;
2884 }
2885 ss << buf;
2886 }
2887 LOG(ERROR) << __func__ << ": " << ss.str();
2888 return (left_bracket == right_bracket) &&
2889 (left_sq_bracket == right_sq_bracket);
2890 }
2891
TEST_F(HasClientTest,test_dumpsys)2892 TEST_F(HasClientTest, test_dumpsys) {
2893 const RawAddress test_address = GetTestAddress(1);
2894
2895 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2896 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2897 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2898 "Preset2"),
2899 }};
2900 SetSampleDatabaseHasPresetsNtf(
2901 test_address,
2902 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2903 bluetooth::has::kFeatureBitWritablePresets |
2904 bluetooth::has::kFeatureBitDynamicPresets,
2905 presets);
2906
2907 uint8_t active_preset_index = 0;
2908 std::vector<PresetInfo> preset_details;
2909
2910 EXPECT_CALL(*callbacks,
2911 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2912 PresetInfoReason::ALL_PRESET_INFO, _))
2913 .Times(1)
2914 .WillOnce(SaveArg<2>(&preset_details));
2915 ON_CALL(*callbacks, OnActivePresetSelected(_, _))
2916 .WillByDefault(SaveArg<1>(&active_preset_index));
2917 TestConnect(test_address);
2918
2919 int sv[2];
2920 ASSERT_EQ(0, socketpair(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK, 0, sv));
2921 int socket_buffer_size = GetSocketBufferSize(sv[0]);
2922
2923 HasClient::Get()->DebugDump(sv[0]);
2924 int dumpsys_byte_cnt = 0;
2925 ASSERT_TRUE(dumpsys_byte_cnt < socket_buffer_size);
2926 ASSERT_TRUE(SimpleJsonValidator(sv[1], &dumpsys_byte_cnt));
2927 }
2928
TEST_F(HasClientTest,test_connect_database_out_of_sync)2929 TEST_F(HasClientTest, test_connect_database_out_of_sync) {
2930 osi_property_set_bool("persist.bluetooth.has.always_use_preset_cache", false);
2931
2932 const RawAddress test_address = GetTestAddress(1);
2933 std::set<HasPreset, HasPreset::ComparatorDesc> has_presets = {{
2934 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2935 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2936 "Preset2"),
2937 }};
2938 SetSampleDatabaseHasPresetsNtf(
2939 test_address,
2940 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2941 bluetooth::has::kFeatureBitWritablePresets |
2942 bluetooth::has::kFeatureBitDynamicPresets,
2943 has_presets);
2944
2945 EXPECT_CALL(*callbacks, OnDeviceAvailable(
2946 test_address,
2947 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2948 bluetooth::has::kFeatureBitWritablePresets |
2949 bluetooth::has::kFeatureBitDynamicPresets));
2950 EXPECT_CALL(*callbacks,
2951 OnConnectionState(ConnectionState::CONNECTED, test_address));
2952 TestConnect(test_address);
2953
2954 ON_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _))
2955 .WillByDefault(
2956 Invoke([this](uint16_t conn_id, uint16_t handle,
2957 std::vector<uint8_t> value, tGATT_WRITE_TYPE write_type,
2958 GATT_WRITE_OP_CB cb, void* cb_data) {
2959 auto* svc = gatt::FindService(services_map[conn_id], handle);
2960 if (svc == nullptr) return;
2961
2962 tGATT_STATUS status = GATT_DATABASE_OUT_OF_SYNC;
2963 if (cb)
2964 cb(conn_id, status, handle, value.size(), value.data(), cb_data);
2965 }));
2966
2967 ON_CALL(gatt_interface, ServiceSearchRequest(_, _)).WillByDefault(Return());
2968 EXPECT_CALL(gatt_interface, ServiceSearchRequest(_, _));
2969 HasClient::Get()->GetPresetInfo(test_address, 1);
2970 }
2971
2972 class HasTypesTest : public ::testing::Test {
2973 protected:
SetUp(void)2974 void SetUp(void) override { mock_function_count_map.clear(); }
2975
TearDown(void)2976 void TearDown(void) override {}
2977 }; // namespace
2978
TEST_F(HasTypesTest,test_has_preset_serialize)2979 TEST_F(HasTypesTest, test_has_preset_serialize) {
2980 HasPreset preset(0x01,
2981 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2982 "My Writable Preset01");
2983
2984 auto sp_sz = preset.SerializedSize();
2985 std::vector<uint8_t> serialized(sp_sz);
2986
2987 ASSERT_EQ(1 + // preset index
2988 1 + // properties
2989 1 + // name length
2990 preset.GetName().length(),
2991 sp_sz);
2992
2993 /* Serialize should move the received buffer pointer by the size of data
2994 */
2995 ASSERT_EQ(preset.Serialize(serialized.data(), serialized.size()),
2996 serialized.data() + serialized.size());
2997
2998 /* Deserialize */
2999 HasPreset clone;
3000 ASSERT_EQ(HasPreset::Deserialize(serialized.data(), serialized.size(), clone),
3001 serialized.data() + serialized.size());
3002
3003 /* Verify */
3004 ASSERT_EQ(preset.GetIndex(), clone.GetIndex());
3005 ASSERT_EQ(preset.GetProperties(), clone.GetProperties());
3006 ASSERT_EQ(preset.GetName(), clone.GetName());
3007 }
3008
TEST_F(HasTypesTest,test_has_preset_serialize_output_buffer_to_small)3009 TEST_F(HasTypesTest, test_has_preset_serialize_output_buffer_to_small) {
3010 HasPreset preset(0x01,
3011 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
3012 "My Writable Preset01");
3013
3014 /* On failure, the offset should still point on .data() */
3015 std::vector<uint8_t> serialized(preset.SerializedSize() - 1);
3016 ASSERT_EQ(preset.Serialize(serialized.data(), serialized.size()),
3017 serialized.data());
3018 ASSERT_EQ(preset.Serialize(serialized.data(), 0), serialized.data());
3019 ASSERT_EQ(preset.Serialize(serialized.data(), 1), serialized.data());
3020 ASSERT_EQ(preset.Serialize(serialized.data(), 10), serialized.data());
3021 }
3022
TEST_F(HasTypesTest,test_has_preset_serialize_name_to_long)3023 TEST_F(HasTypesTest, test_has_preset_serialize_name_to_long) {
3024 HasPreset preset(0x01,
3025 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
3026 "This name is more than 40 characters long");
3027
3028 /* On failure, the offset should still point on .data() */
3029 std::vector<uint8_t> serialized(preset.SerializedSize());
3030 EXPECT_EQ(preset.Serialize(serialized.data(), serialized.size()),
3031 serialized.data());
3032 }
3033
TEST_F(HasTypesTest,test_has_preset_deserialize_input_buffer_to_small)3034 TEST_F(HasTypesTest, test_has_preset_deserialize_input_buffer_to_small) {
3035 HasPreset preset(0x01,
3036 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
3037 "My Writable Preset01");
3038
3039 std::vector<uint8_t> serialized(preset.SerializedSize());
3040
3041 /* Serialize should move the received buffer pointer by the size of data
3042 */
3043 ASSERT_EQ(preset.Serialize(serialized.data(), serialized.size()),
3044 serialized.data() + serialized.size());
3045
3046 /* Deserialize */
3047 HasPreset clone;
3048 ASSERT_EQ(HasPreset::Deserialize(serialized.data(), 0, clone),
3049 serialized.data());
3050 ASSERT_EQ(HasPreset::Deserialize(serialized.data(), 1, clone),
3051 serialized.data());
3052 ASSERT_EQ(HasPreset::Deserialize(serialized.data(), 11, clone),
3053 serialized.data());
3054 ASSERT_EQ(
3055 HasPreset::Deserialize(serialized.data(), serialized.size() - 1, clone),
3056 serialized.data());
3057 }
3058
TEST_F(HasTypesTest,test_has_presets_serialize)3059 TEST_F(HasTypesTest, test_has_presets_serialize) {
3060 HasPreset preset(0x01,
3061 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
3062 "My Writable Preset01");
3063
3064 HasPreset preset2(0x02, 0, "Nonwritable Unavailable Preset");
3065
3066 HasDevice has_device(GetTestAddress(1));
3067 has_device.has_presets.insert(preset);
3068 has_device.has_presets.insert(preset2);
3069
3070 auto out_buf_sz = has_device.SerializedPresetsSize();
3071 ASSERT_EQ(out_buf_sz, preset.SerializedSize() + preset2.SerializedSize() + 2);
3072
3073 /* Serialize should append to the vector */
3074 std::vector<uint8_t> serialized;
3075 ASSERT_TRUE(has_device.SerializePresets(serialized));
3076 ASSERT_EQ(out_buf_sz, serialized.size());
3077
3078 /* Deserialize */
3079 HasDevice clone(GetTestAddress(1));
3080 ASSERT_TRUE(HasDevice::DeserializePresets(serialized.data(),
3081 serialized.size(), clone));
3082
3083 /* Verify */
3084 ASSERT_EQ(clone.has_presets.size(), has_device.has_presets.size());
3085 ASSERT_NE(0u, clone.has_presets.count(0x01));
3086 ASSERT_NE(0u, clone.has_presets.count(0x02));
3087
3088 ASSERT_EQ(clone.has_presets.find(0x01)->GetIndex(),
3089 has_device.has_presets.find(0x01)->GetIndex());
3090 ASSERT_EQ(clone.has_presets.find(0x01)->GetProperties(),
3091 has_device.has_presets.find(0x01)->GetProperties());
3092 ASSERT_EQ(clone.has_presets.find(0x01)->GetName(),
3093 has_device.has_presets.find(0x01)->GetName());
3094
3095 ASSERT_EQ(clone.has_presets.find(0x02)->GetIndex(),
3096 has_device.has_presets.find(0x02)->GetIndex());
3097 ASSERT_EQ(clone.has_presets.find(0x02)->GetProperties(),
3098 has_device.has_presets.find(0x02)->GetProperties());
3099 ASSERT_EQ(clone.has_presets.find(0x02)->GetName(),
3100 has_device.has_presets.find(0x02)->GetName());
3101 }
3102
TEST_F(HasTypesTest,test_group_op_coordinator_init)3103 TEST_F(HasTypesTest, test_group_op_coordinator_init) {
3104 HasCtpGroupOpCoordinator::Initialize([](void*) {
3105 /* Do nothing */
3106 });
3107 ASSERT_EQ(0u, HasCtpGroupOpCoordinator::ref_cnt);
3108 auto address1 = GetTestAddress(1);
3109 auto address2 = GetTestAddress(2);
3110
3111 HasCtpGroupOpCoordinator wrapper(
3112 {address1, address2},
3113 HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6));
3114 ASSERT_EQ(2u, wrapper.ref_cnt);
3115
3116 HasCtpGroupOpCoordinator::Cleanup();
3117 ASSERT_EQ(0u, wrapper.ref_cnt);
3118
3119 ASSERT_EQ(1, mock_function_count_map["alarm_free"]);
3120 ASSERT_EQ(1, mock_function_count_map["alarm_new"]);
3121 }
3122
TEST_F(HasTypesTest,test_group_op_coordinator_copy)3123 TEST_F(HasTypesTest, test_group_op_coordinator_copy) {
3124 HasCtpGroupOpCoordinator::Initialize([](void*) {
3125 /* Do nothing */
3126 });
3127 ASSERT_EQ(0u, HasCtpGroupOpCoordinator::ref_cnt);
3128 auto address1 = GetTestAddress(1);
3129 auto address2 = GetTestAddress(2);
3130
3131 HasCtpGroupOpCoordinator wrapper(
3132 {address1, address2},
3133 HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6));
3134 HasCtpGroupOpCoordinator wrapper2(
3135 {address1},
3136 HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6));
3137 ASSERT_EQ(3u, wrapper.ref_cnt);
3138 HasCtpGroupOpCoordinator wrapper3 = wrapper2;
3139 auto* wrapper4 =
3140 new HasCtpGroupOpCoordinator(HasCtpGroupOpCoordinator(wrapper2));
3141 ASSERT_EQ(5u, wrapper.ref_cnt);
3142
3143 delete wrapper4;
3144 ASSERT_EQ(4u, wrapper.ref_cnt);
3145
3146 HasCtpGroupOpCoordinator::Cleanup();
3147 ASSERT_EQ(0u, wrapper.ref_cnt);
3148
3149 ASSERT_EQ(1, mock_function_count_map["alarm_free"]);
3150 ASSERT_EQ(1, mock_function_count_map["alarm_new"]);
3151 }
3152
TEST_F(HasTypesTest,test_group_op_coordinator_completion)3153 TEST_F(HasTypesTest, test_group_op_coordinator_completion) {
3154 HasCtpGroupOpCoordinator::Initialize([](void*) {
3155 /* Do nothing */
3156 LOG(INFO) << __func__ << " callback call";
3157 });
3158 ASSERT_EQ(0u, HasCtpGroupOpCoordinator::ref_cnt);
3159 auto address1 = GetTestAddress(1);
3160 auto address2 = GetTestAddress(2);
3161 auto address3 = GetTestAddress(3);
3162
3163 HasCtpGroupOpCoordinator wrapper(
3164 {address1, address3},
3165 HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6));
3166 HasCtpGroupOpCoordinator wrapper2(
3167 {address2},
3168 HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6));
3169 ASSERT_EQ(3u, wrapper.ref_cnt);
3170
3171 ASSERT_FALSE(wrapper.IsFullyCompleted());
3172
3173 wrapper.SetCompleted(address1);
3174 ASSERT_EQ(2u, wrapper.ref_cnt);
3175
3176 wrapper.SetCompleted(address3);
3177 ASSERT_EQ(1u, wrapper.ref_cnt);
3178 ASSERT_FALSE(wrapper.IsFullyCompleted());
3179
3180 /* Non existing address completion */
3181 wrapper.SetCompleted(address2);
3182 ASSERT_EQ(1u, wrapper.ref_cnt);
3183
3184 /* Last device address completion */
3185 wrapper2.SetCompleted(address2);
3186 ASSERT_TRUE(wrapper.IsFullyCompleted());
3187 ASSERT_EQ(0u, wrapper.ref_cnt);
3188
3189 HasCtpGroupOpCoordinator::Cleanup();
3190
3191 ASSERT_EQ(1, mock_function_count_map["alarm_free"]);
3192 ASSERT_EQ(1, mock_function_count_map["alarm_new"]);
3193 }
3194
3195 } // namespace
3196 } // namespace internal
3197 } // namespace has
3198 } // namespace bluetooth
3199