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