1 /* test_unicast_stop.c - unit test for unicast stop procedure */
2
3 /*
4 * Copyright (c) 2024 Nordic Semiconductor ASA
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <errno.h>
10 #include <stdbool.h>
11 #include <stddef.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include <zephyr/autoconf.h>
16 #include <zephyr/bluetooth/audio/audio.h>
17 #include <zephyr/bluetooth/audio/bap.h>
18 #include <zephyr/bluetooth/audio/bap_lc3_preset.h>
19 #include <zephyr/bluetooth/audio/cap.h>
20 #include <zephyr/bluetooth/hci_types.h>
21 #include <zephyr/fff.h>
22 #include <zephyr/sys/slist.h>
23 #include <zephyr/sys/util.h>
24 #include <sys/errno.h>
25
26 #include "bap_endpoint.h"
27 #include "cap_initiator.h"
28 #include "conn.h"
29 #include "expects_util.h"
30 #include "test_common.h"
31 #include "ztest_assert.h"
32 #include "ztest_test.h"
33
34 struct cap_initiator_test_unicast_stop_fixture {
35 struct bt_cap_stream cap_streams[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT];
36 struct bt_bap_ep eps[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT];
37 struct bt_bap_unicast_group unicast_group;
38 struct bt_conn conns[CONFIG_BT_MAX_CONN];
39 struct bt_bap_lc3_preset preset;
40 };
41
cap_initiator_test_unicast_stop_fixture_init(struct cap_initiator_test_unicast_stop_fixture * fixture)42 static void cap_initiator_test_unicast_stop_fixture_init(
43 struct cap_initiator_test_unicast_stop_fixture *fixture)
44 {
45 fixture->preset = (struct bt_bap_lc3_preset)BT_BAP_LC3_UNICAST_PRESET_16_2_1(
46 BT_AUDIO_LOCATION_MONO_AUDIO, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
47
48 for (size_t i = 0U; i < ARRAY_SIZE(fixture->conns); i++) {
49 test_conn_init(&fixture->conns[i]);
50 }
51
52 for (size_t i = 0U; i < ARRAY_SIZE(fixture->eps); i++) {
53 fixture->eps[i].dir = (i & 1) + 1; /* Makes it either 1 or 2 (sink or source)*/
54 }
55
56 for (size_t i = 0U; i < ARRAY_SIZE(fixture->cap_streams); i++) {
57 struct bt_cap_stream *cap_stream = &fixture->cap_streams[i];
58 struct bt_bap_stream *bap_stream = &cap_stream->bap_stream;
59
60 sys_slist_append(&fixture->unicast_group.streams, &bap_stream->_node);
61 bap_stream->group = &fixture->unicast_group;
62 }
63 }
64
cap_initiator_test_unicast_stop_setup(void)65 static void *cap_initiator_test_unicast_stop_setup(void)
66 {
67 struct cap_initiator_test_unicast_stop_fixture *fixture;
68
69 fixture = malloc(sizeof(*fixture));
70 zassert_not_null(fixture);
71
72 return fixture;
73 }
74
cap_initiator_test_unicast_stop_before(void * f)75 static void cap_initiator_test_unicast_stop_before(void *f)
76 {
77 int err;
78
79 memset(f, 0, sizeof(struct cap_initiator_test_unicast_stop_fixture));
80 cap_initiator_test_unicast_stop_fixture_init(f);
81
82 err = bt_cap_initiator_register_cb(&mock_cap_initiator_cb);
83 zassert_equal(0, err, "Unexpected return value %d", err);
84 }
85
cap_initiator_test_unicast_stop_after(void * f)86 static void cap_initiator_test_unicast_stop_after(void *f)
87 {
88 struct cap_initiator_test_unicast_stop_fixture *fixture = f;
89
90 bt_cap_initiator_unregister_cb(&mock_cap_initiator_cb);
91
92 for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
93 mock_bt_conn_disconnected(&fixture->conns[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
94 }
95
96 /* In the case of a test failing, we cancel the procedure so that subsequent won't fail */
97 bt_cap_initiator_unicast_audio_cancel();
98 }
99
cap_initiator_test_unicast_stop_teardown(void * f)100 static void cap_initiator_test_unicast_stop_teardown(void *f)
101 {
102 free(f);
103 }
104
105 ZTEST_SUITE(cap_initiator_test_unicast_stop, NULL, cap_initiator_test_unicast_stop_setup,
106 cap_initiator_test_unicast_stop_before, cap_initiator_test_unicast_stop_after,
107 cap_initiator_test_unicast_stop_teardown);
108
ZTEST_F(cap_initiator_test_unicast_stop,test_initiator_unicast_stop_disable_state_codec_configured)109 static ZTEST_F(cap_initiator_test_unicast_stop,
110 test_initiator_unicast_stop_disable_state_codec_configured)
111 {
112 struct bt_cap_stream *streams[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
113 const struct bt_cap_unicast_audio_stop_param param = {
114 .type = BT_CAP_SET_TYPE_AD_HOC,
115 .count = ARRAY_SIZE(streams),
116 .streams = streams,
117 .release = false,
118 };
119 int err;
120
121 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
122 streams[i] = &fixture->cap_streams[i];
123
124 test_unicast_set_state(streams[i], &fixture->conns[i % ARRAY_SIZE(fixture->conns)],
125 &fixture->eps[i], &fixture->preset,
126 BT_BAP_EP_STATE_CODEC_CONFIGURED);
127 }
128
129 err = bt_cap_initiator_unicast_audio_stop(¶m);
130 zassert_equal(err, -EALREADY, "Unexpected return value %d", err);
131
132 zexpect_call_count("bt_cap_initiator_cb.unicast_stop_complete_cb", 0,
133 mock_cap_initiator_unicast_stop_complete_cb_fake.call_count);
134
135 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
136 const struct bt_bap_stream *bap_stream = &fixture->cap_streams[i].bap_stream;
137 const enum bt_bap_ep_state state = bap_stream->ep->status.state;
138
139 zassert_equal(state, BT_BAP_EP_STATE_CODEC_CONFIGURED,
140 "[%zu]: Stream %p unexpected state: %d", i, bap_stream, state);
141 }
142 }
143
ZTEST_F(cap_initiator_test_unicast_stop,test_initiator_unicast_stop_disable_state_qos_configured)144 static ZTEST_F(cap_initiator_test_unicast_stop,
145 test_initiator_unicast_stop_disable_state_qos_configured)
146 {
147 struct bt_cap_stream *streams[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
148 const struct bt_cap_unicast_audio_stop_param param = {
149 .type = BT_CAP_SET_TYPE_AD_HOC,
150 .count = ARRAY_SIZE(streams),
151 .streams = streams,
152 .release = false,
153 };
154 int err;
155
156 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
157 streams[i] = &fixture->cap_streams[i];
158
159 test_unicast_set_state(streams[i], &fixture->conns[i % ARRAY_SIZE(fixture->conns)],
160 &fixture->eps[i], &fixture->preset,
161 BT_BAP_EP_STATE_QOS_CONFIGURED);
162 }
163
164 err = bt_cap_initiator_unicast_audio_stop(¶m);
165 zassert_equal(err, -EALREADY, "Unexpected return value %d", err);
166
167 zexpect_call_count("bt_cap_initiator_cb.unicast_stop_complete_cb", 0,
168 mock_cap_initiator_unicast_stop_complete_cb_fake.call_count);
169
170 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
171 const struct bt_bap_stream *bap_stream = &fixture->cap_streams[i].bap_stream;
172 const enum bt_bap_ep_state state = bap_stream->ep->status.state;
173
174 zassert_equal(state, BT_BAP_EP_STATE_QOS_CONFIGURED,
175 "[%zu]: Stream %p unexpected state: %d", i, bap_stream, state);
176 }
177 }
178
ZTEST_F(cap_initiator_test_unicast_stop,test_initiator_unicast_stop_disable_state_enabling)179 static ZTEST_F(cap_initiator_test_unicast_stop, test_initiator_unicast_stop_disable_state_enabling)
180 {
181 struct bt_cap_stream *streams[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
182 const struct bt_cap_unicast_audio_stop_param param = {
183 .type = BT_CAP_SET_TYPE_AD_HOC,
184 .count = ARRAY_SIZE(streams),
185 .streams = streams,
186 .release = false,
187 };
188 int err;
189
190 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
191 streams[i] = &fixture->cap_streams[i];
192
193 test_unicast_set_state(streams[i], &fixture->conns[i % ARRAY_SIZE(fixture->conns)],
194 &fixture->eps[i], &fixture->preset,
195 BT_BAP_EP_STATE_ENABLING);
196 }
197
198 err = bt_cap_initiator_unicast_audio_stop(¶m);
199 zassert_equal(err, 0, "Unexpected return value %d", err);
200
201 zexpect_call_count("bt_cap_initiator_cb.unicast_stop_complete_cb", 1,
202 mock_cap_initiator_unicast_stop_complete_cb_fake.call_count);
203
204 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
205 const struct bt_bap_stream *bap_stream = &fixture->cap_streams[i].bap_stream;
206 const enum bt_bap_ep_state state = bap_stream->ep->status.state;
207
208 zassert_equal(state, BT_BAP_EP_STATE_QOS_CONFIGURED,
209 "[%zu]: Stream %p unexpected state: %d", i, bap_stream, state);
210 }
211 }
212
ZTEST_F(cap_initiator_test_unicast_stop,test_initiator_unicast_stop_disable_state_streaming)213 static ZTEST_F(cap_initiator_test_unicast_stop, test_initiator_unicast_stop_disable_state_streaming)
214 {
215 struct bt_cap_stream *streams[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
216 const struct bt_cap_unicast_audio_stop_param param = {
217 .type = BT_CAP_SET_TYPE_AD_HOC,
218 .count = ARRAY_SIZE(streams),
219 .streams = streams,
220 .release = false,
221 };
222 int err;
223
224 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
225 streams[i] = &fixture->cap_streams[i];
226
227 test_unicast_set_state(streams[i], &fixture->conns[i % ARRAY_SIZE(fixture->conns)],
228 &fixture->eps[i], &fixture->preset,
229 BT_BAP_EP_STATE_STREAMING);
230 }
231
232 err = bt_cap_initiator_unicast_audio_stop(¶m);
233 zassert_equal(err, 0, "Unexpected return value %d", err);
234
235 zexpect_call_count("bt_cap_initiator_cb.unicast_stop_complete_cb", 1,
236 mock_cap_initiator_unicast_stop_complete_cb_fake.call_count);
237
238 for (size_t i = 0U; i < ARRAY_SIZE(fixture->cap_streams); i++) {
239 const struct bt_bap_stream *bap_stream = &fixture->cap_streams[i].bap_stream;
240 const enum bt_bap_ep_state state = bap_stream->ep->status.state;
241
242 zassert_equal(state, BT_BAP_EP_STATE_QOS_CONFIGURED,
243 "[%zu]: Stream %p unexpected state: %d", i, bap_stream, state);
244 }
245 }
246
ZTEST_F(cap_initiator_test_unicast_stop,test_initiator_unicast_stop_release_state_codec_configured)247 static ZTEST_F(cap_initiator_test_unicast_stop,
248 test_initiator_unicast_stop_release_state_codec_configured)
249 {
250 struct bt_cap_stream *streams[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
251 const struct bt_cap_unicast_audio_stop_param param = {
252 .type = BT_CAP_SET_TYPE_AD_HOC,
253 .count = ARRAY_SIZE(streams),
254 .streams = streams,
255 .release = true,
256 };
257 int err;
258
259 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
260 streams[i] = &fixture->cap_streams[i];
261
262 test_unicast_set_state(streams[i], &fixture->conns[i % ARRAY_SIZE(fixture->conns)],
263 &fixture->eps[i], &fixture->preset,
264 BT_BAP_EP_STATE_CODEC_CONFIGURED);
265 }
266
267 err = bt_cap_initiator_unicast_audio_stop(¶m);
268 zassert_equal(err, -EALREADY, "Unexpected return value %d", err);
269
270 zexpect_call_count("bt_cap_initiator_cb.unicast_stop_complete_cb", 0,
271 mock_cap_initiator_unicast_stop_complete_cb_fake.call_count);
272
273 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
274 const struct bt_bap_stream *bap_stream = &fixture->cap_streams[i].bap_stream;
275 const enum bt_bap_ep_state state = bap_stream->ep->status.state;
276
277 zassert_equal(state, BT_BAP_EP_STATE_CODEC_CONFIGURED,
278 "[%zu]: Stream %p unexpected state: %d", i, bap_stream, state);
279 }
280 }
281
ZTEST_F(cap_initiator_test_unicast_stop,test_initiator_unicast_stop_release_state_qos_configured)282 static ZTEST_F(cap_initiator_test_unicast_stop,
283 test_initiator_unicast_stop_release_state_qos_configured)
284 {
285 struct bt_cap_stream *streams[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
286 const struct bt_cap_unicast_audio_stop_param param = {
287 .type = BT_CAP_SET_TYPE_AD_HOC,
288 .count = ARRAY_SIZE(streams),
289 .streams = streams,
290 .release = true,
291 };
292 int err;
293
294 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
295 streams[i] = &fixture->cap_streams[i];
296
297 test_unicast_set_state(streams[i], &fixture->conns[i % ARRAY_SIZE(fixture->conns)],
298 &fixture->eps[i], &fixture->preset,
299 BT_BAP_EP_STATE_QOS_CONFIGURED);
300 }
301
302 err = bt_cap_initiator_unicast_audio_stop(¶m);
303 zassert_equal(err, 0, "Unexpected return value %d", err);
304
305 zexpect_call_count("bt_cap_initiator_cb.unicast_stop_complete_cb", 1,
306 mock_cap_initiator_unicast_stop_complete_cb_fake.call_count);
307
308 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
309 const struct bt_bap_stream *bap_stream = &fixture->cap_streams[i].bap_stream;
310 const enum bt_bap_ep_state state = fixture->eps[i].status.state;
311
312 zassert_equal(state, BT_BAP_EP_STATE_IDLE, "[%zu]: Stream %p unexpected state: %d",
313 i, bap_stream, state);
314 }
315 }
316
ZTEST_F(cap_initiator_test_unicast_stop,test_initiator_unicast_stop_release_state_enabling)317 static ZTEST_F(cap_initiator_test_unicast_stop, test_initiator_unicast_stop_release_state_enabling)
318 {
319 struct bt_cap_stream *streams[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
320 const struct bt_cap_unicast_audio_stop_param param = {
321 .type = BT_CAP_SET_TYPE_AD_HOC,
322 .count = ARRAY_SIZE(streams),
323 .streams = streams,
324 .release = true,
325 };
326 int err;
327
328 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
329 streams[i] = &fixture->cap_streams[i];
330
331 test_unicast_set_state(streams[i], &fixture->conns[i % ARRAY_SIZE(fixture->conns)],
332 &fixture->eps[i], &fixture->preset,
333 BT_BAP_EP_STATE_ENABLING);
334 }
335
336 err = bt_cap_initiator_unicast_audio_stop(¶m);
337 zassert_equal(err, 0, "Unexpected return value %d", err);
338
339 zexpect_call_count("bt_cap_initiator_cb.unicast_stop_complete_cb", 1,
340 mock_cap_initiator_unicast_stop_complete_cb_fake.call_count);
341
342 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
343 const struct bt_bap_stream *bap_stream = &fixture->cap_streams[i].bap_stream;
344 const enum bt_bap_ep_state state = fixture->eps[i].status.state;
345
346 zassert_equal(state, BT_BAP_EP_STATE_IDLE, "[%zu]: Stream %p unexpected state: %d",
347 i, bap_stream, state);
348 }
349 }
350
ZTEST_F(cap_initiator_test_unicast_stop,test_initiator_unicast_stop_release_state_streaming)351 static ZTEST_F(cap_initiator_test_unicast_stop, test_initiator_unicast_stop_release_state_streaming)
352 {
353 struct bt_cap_stream *streams[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
354 const struct bt_cap_unicast_audio_stop_param param = {
355 .type = BT_CAP_SET_TYPE_AD_HOC,
356 .count = ARRAY_SIZE(streams),
357 .streams = streams,
358 .release = true,
359 };
360 int err;
361
362 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
363 streams[i] = &fixture->cap_streams[i];
364
365 test_unicast_set_state(streams[i], &fixture->conns[i % ARRAY_SIZE(fixture->conns)],
366 &fixture->eps[i], &fixture->preset,
367 BT_BAP_EP_STATE_ENABLING);
368 }
369
370 err = bt_cap_initiator_unicast_audio_stop(¶m);
371 zassert_equal(err, 0, "Unexpected return value %d", err);
372
373 zexpect_call_count("bt_cap_initiator_cb.unicast_stop_complete_cb", 1,
374 mock_cap_initiator_unicast_stop_complete_cb_fake.call_count);
375
376 for (size_t i = 0U; i < ARRAY_SIZE(fixture->cap_streams); i++) {
377 const struct bt_bap_stream *bap_stream = &fixture->cap_streams[i].bap_stream;
378 const enum bt_bap_ep_state state = fixture->eps[i].status.state;
379
380 zassert_equal(state, BT_BAP_EP_STATE_IDLE, "[%zu]: Stream %p unexpected state: %d",
381 i, bap_stream, state);
382 }
383 }
384
ZTEST_F(cap_initiator_test_unicast_stop,test_initiator_unicast_stop_inval_param_null)385 static ZTEST_F(cap_initiator_test_unicast_stop, test_initiator_unicast_stop_inval_param_null)
386 {
387 int err;
388
389 err = bt_cap_initiator_unicast_audio_stop(NULL);
390 zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
391
392 zexpect_call_count("bt_cap_initiator_cb.unicast_stop_complete_cb", 0,
393 mock_cap_initiator_unicast_stop_complete_cb_fake.call_count);
394 }
395
ZTEST_F(cap_initiator_test_unicast_stop,test_initiator_unicast_stop_inval_param_null_streams)396 static ZTEST_F(cap_initiator_test_unicast_stop,
397 test_initiator_unicast_stop_inval_param_null_streams)
398 {
399 const struct bt_cap_unicast_audio_stop_param param = {
400 .type = BT_CAP_SET_TYPE_AD_HOC,
401 .count = CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT,
402 .streams = NULL,
403 .release = true,
404 };
405 int err;
406
407 err = bt_cap_initiator_unicast_audio_stop(¶m);
408 zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
409
410 zexpect_call_count("bt_cap_initiator_cb.unicast_stop_complete_cb", 0,
411 mock_cap_initiator_unicast_stop_complete_cb_fake.call_count);
412 }
413
ZTEST_F(cap_initiator_test_unicast_stop,test_initiator_unicast_stop_inval_missing_cas)414 static ZTEST_F(cap_initiator_test_unicast_stop, test_initiator_unicast_stop_inval_missing_cas)
415 {
416 struct bt_cap_stream *streams[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
417 const struct bt_cap_unicast_audio_stop_param param = {
418 .type = BT_CAP_SET_TYPE_CSIP, /* CSIP requires CAS */
419 .count = ARRAY_SIZE(streams),
420 .streams = streams,
421 .release = true,
422 };
423 int err;
424
425 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
426 streams[i] = &fixture->cap_streams[i];
427
428 test_unicast_set_state(streams[i], &fixture->conns[i % ARRAY_SIZE(fixture->conns)],
429 &fixture->eps[i], &fixture->preset,
430 BT_BAP_EP_STATE_STREAMING);
431 }
432
433 err = bt_cap_initiator_unicast_audio_stop(¶m);
434 zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
435
436 zexpect_call_count("bt_cap_initiator_cb.unicast_stop_complete_cb", 0,
437 mock_cap_initiator_unicast_stop_complete_cb_fake.call_count);
438 }
439
ZTEST_F(cap_initiator_test_unicast_stop,test_initiator_unicast_stop_inval_param_zero_count)440 static ZTEST_F(cap_initiator_test_unicast_stop, test_initiator_unicast_stop_inval_param_zero_count)
441 {
442 struct bt_cap_stream *streams[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
443 const struct bt_cap_unicast_audio_stop_param param = {
444 .type = BT_CAP_SET_TYPE_AD_HOC,
445 .count = 0U,
446 .streams = streams,
447 .release = true,
448 };
449 int err;
450
451 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
452 streams[i] = &fixture->cap_streams[i];
453 }
454
455 err = bt_cap_initiator_unicast_audio_stop(¶m);
456 zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
457
458 zexpect_call_count("bt_cap_initiator_cb.unicast_stop_complete_cb", 0,
459 mock_cap_initiator_unicast_stop_complete_cb_fake.call_count);
460 }
461
ZTEST_F(cap_initiator_test_unicast_stop,test_initiator_unicast_stop_inval_param_inval_count)462 static ZTEST_F(cap_initiator_test_unicast_stop, test_initiator_unicast_stop_inval_param_inval_count)
463 {
464 struct bt_cap_stream *streams[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
465 const struct bt_cap_unicast_audio_stop_param param = {
466 .type = BT_CAP_SET_TYPE_AD_HOC,
467 .count = CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT + 1U,
468 .streams = streams,
469 .release = true,
470 };
471 int err;
472
473 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
474 streams[i] = &fixture->cap_streams[i];
475 }
476
477 err = bt_cap_initiator_unicast_audio_stop(¶m);
478 zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
479
480 zexpect_call_count("bt_cap_initiator_cb.unicast_stop_complete_cb", 0,
481 mock_cap_initiator_unicast_stop_complete_cb_fake.call_count);
482 }
483