diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 51ba19b2350..ae94530214c 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -3283,6 +3283,8 @@ int bt_ascs_unregister(void) for (size_t i = 0; i < ARRAY_SIZE(ascs.ase_pool); i++) { if (ascs.ase_pool[i].ep.status.state != BT_BAP_EP_STATE_IDLE) { + LOG_DBG("[%zu] ase %p not in idle state: %s", i, &ascs.ase_pool[i].ep, + bt_bap_ep_state_str(ascs.ase_pool[i].ep.status.state)); return -EBUSY; } } diff --git a/tests/bluetooth/audio/ascs/CMakeLists.txt b/tests/bluetooth/audio/ascs/CMakeLists.txt index 5fb4df5f683..6b4b0311daa 100644 --- a/tests/bluetooth/audio/ascs/CMakeLists.txt +++ b/tests/bluetooth/audio/ascs/CMakeLists.txt @@ -16,6 +16,7 @@ target_sources(testbinary PRIVATE src/main.c src/test_ase_control_params.c + src/test_ase_register.c src/test_ase_state_transition_invalid.c src/test_ase_state_transition.c src/test_common.c diff --git a/tests/bluetooth/audio/ascs/src/main.c b/tests/bluetooth/audio/ascs/src/main.c index 77f6f32ec2a..aca746650a2 100644 --- a/tests/bluetooth/audio/ascs/src/main.c +++ b/tests/bluetooth/audio/ascs/src/main.c @@ -3,10 +3,12 @@ /* * Copyright (c) 2023 Codecoup * Copyright (c) 2024 Demant A/S + * Copyright (c) 2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -34,6 +36,7 @@ #include "pacs.h" #include "test_common.h" +#include "ztest_assert.h" DEFINE_FFF_GLOBALS; @@ -70,6 +73,7 @@ static void ascs_test_suite_fixture_init(struct ascs_test_suite_fixture *fixture memset(fixture, 0, sizeof(*fixture)); err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, 0, "Unexpected err response %d", err); fixture->ase_cp = test_ase_control_point_get(); @@ -109,11 +113,17 @@ static void ascs_test_suite_teardown(void *f) static void ascs_test_suite_after(void *f) { - /* We skip error-checking this, as somehow this breaks the tests, due to seemingly - * memory corruption, causing incorrect lookup of attributes in following 'before' calls - */ - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); - bt_bap_unicast_server_unregister(); + int err; + + /* If any of these fails, it's a fatal error for any tests running afterwards */ + err = bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); + zassert_true(err == 0 || err == -EALREADY, "Unexpected err response %d", err); + + /* Sleep to trigger any pending state changes from unregister_cb */ + k_sleep(K_SECONDS(1)); + + err = bt_bap_unicast_server_unregister(); + zassert_equal(err, 0, "Unexpected err response %d", err); } ZTEST_SUITE(ascs_test_suite, NULL, ascs_test_suite_setup, ascs_test_suite_before, @@ -153,158 +163,6 @@ ZTEST_F(ascs_test_suite, test_sink_ase_read_state_idle) zassert_equal(0x00, hdr.ase_state, "unexpected ASE_State 0x%02x", hdr.ase_state); } -ZTEST_F(ascs_test_suite, test_cb_register_without_ascs_registered) -{ - int err; - - /* Unregister ASCS, as its registered through setup */ - err = bt_bap_unicast_server_unregister(); - zassert_equal(err, 0, "unexpected err response %d", err); - - err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); - zassert_equal(err, -ENOTSUP, "unexpected err response %d", err); -} - -ZTEST_F(ascs_test_suite, test_ascs_register_with_null_param) -{ - int err; - - /* Unregister ASCS, as its registered through setup */ - err = bt_bap_unicast_server_unregister(); - zassert_equal(err, 0, "unexpected err response %d", err); - - err = bt_bap_unicast_server_register(NULL); - zassert_equal(err, -EINVAL, "unexpected err response %d", err); -} - -ZTEST_F(ascs_test_suite, test_ascs_register_twice) -{ - int err; - struct bt_bap_unicast_server_register_param param = { - CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, - CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT - }; - - /* Setup already registered once, so calling once here should be sufficient */ - err = bt_bap_unicast_server_register(¶m); - zassert_equal(err, -EALREADY, "unexpected err response %d", err); -} - -ZTEST_F(ascs_test_suite, test_ascs_register_too_many_sinks) -{ - int err; - struct bt_bap_unicast_server_register_param param = { - CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + 1, - CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT - }; - - /* Unregister ASCS, as its registered through setup */ - err = bt_bap_unicast_server_unregister(); - zassert_equal(err, 0, "unexpected err response %d", err); - - err = bt_bap_unicast_server_register(¶m); - zassert_equal(err, -EINVAL, "unexpected err response %d", err); -} - -ZTEST_F(ascs_test_suite, test_ascs_register_too_many_sources) -{ - int err; - struct bt_bap_unicast_server_register_param param = { - CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, - CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1 - }; - - /* Unregister ASCS, as its registered through setup */ - err = bt_bap_unicast_server_unregister(); - zassert_equal(err, 0, "unexpected err response %d", err); - - err = bt_bap_unicast_server_register(¶m); - zassert_equal(err, -EINVAL, "unexpected err response %d", err); -} - -ZTEST_F(ascs_test_suite, test_ascs_register_zero_ases) -{ - int err; - struct bt_bap_unicast_server_register_param param = { - 0, - 0 - }; - - /* Unregister ASCS, as its registered through setup */ - err = bt_bap_unicast_server_unregister(); - zassert_equal(err, 0, "unexpected err response %d", err); - - err = bt_bap_unicast_server_register(¶m); - zassert_equal(err, -EINVAL, "unexpected err response %d", err); -} - -ZTEST_F(ascs_test_suite, test_ascs_register_fewer_than_max_ases) -{ - int err; - struct bt_bap_unicast_server_register_param param = { - CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 ? CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT - 1 : 0, - CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 ? CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT - 1 : 0 - }; - - /* Unregister ASCS, as its registered through setup */ - err = bt_bap_unicast_server_unregister(); - zassert_equal(err, 0, "unexpected err response %d", err); - - err = bt_bap_unicast_server_register(¶m); - zassert_equal(err, 0, "unexpected err response %d", err); -} - -ZTEST_F(ascs_test_suite, test_ascs_unregister_without_register) -{ - int err; - - /* Unregister ASCS, as its registered through setup */ - err = bt_bap_unicast_server_unregister(); - zassert_equal(err, 0, "unexpected err response %d", err); - - err = bt_bap_unicast_server_unregister(); - zassert_equal(err, -EALREADY, "unexpected err response %d", err); -} - -ZTEST_F(ascs_test_suite, test_ascs_unregister_with_ases_in_config_state) -{ - const struct test_ase_chrc_value_hdr *hdr; - const struct bt_gatt_attr *ase; - struct bt_bap_stream *stream = &fixture->stream; - struct bt_conn *conn = &fixture->conn; - struct bt_gatt_notify_params *notify_params; - uint8_t ase_id; - int err; - - if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) { - ase = fixture->ase_snk.attr; - ase_id = fixture->ase_snk.id; - } else { - ase = fixture->ase_src.attr; - ase_id = fixture->ase_src.id; - } - - zexpect_not_null(ase); - zexpect_true(ase_id != 0x00); - - err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); - zassert_equal(err, 0, "unexpected err response %d", err); - - /* Set ASE to non-idle state */ - test_ase_control_client_config_codec(conn, ase_id, stream); - - err = bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); - zassert_equal(err, 0, "unexpected err response %d", err); - - err = bt_bap_unicast_server_unregister(); - - /* Expected to notify the upper layers */ - expect_bt_bap_unicast_server_cb_release_called_once(stream); - expect_bt_bap_stream_ops_released_called_once(stream); - - zassert_equal(err, 0, "unexpected err response %d", err); -} - ZTEST_F(ascs_test_suite, test_release_ase_on_callback_unregister) { const struct test_ase_chrc_value_hdr *hdr; @@ -424,8 +282,6 @@ ZTEST_F(ascs_test_suite, test_release_ase_on_acl_disconnection) /* Mock CIS disconnection */ mock_bt_iso_disconnected(chan, BT_HCI_ERR_CONN_TIMEOUT); - - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } ZTEST_F(ascs_test_suite, test_release_ase_pair_on_acl_disconnection) @@ -486,8 +342,6 @@ ZTEST_F(ascs_test_suite, test_release_ase_pair_on_acl_disconnection) /* Mock CIS disconnection */ mock_bt_iso_disconnected(chan, BT_HCI_ERR_CONN_TIMEOUT); - - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } ZTEST_F(ascs_test_suite, test_recv_in_streaming_state) @@ -514,8 +368,6 @@ ZTEST_F(ascs_test_suite, test_recv_in_streaming_state) /* Verification */ expect_bt_bap_stream_ops_recv_called_once(stream, &info, &buf); - - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } ZTEST_F(ascs_test_suite, test_recv_in_enabling_state) @@ -547,8 +399,6 @@ ZTEST_F(ascs_test_suite, test_recv_in_enabling_state) /* Verification */ expect_bt_bap_stream_ops_recv_not_called(); - - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } ZTEST_F(ascs_test_suite, test_cis_link_loss_in_streaming_state) @@ -584,8 +434,6 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_streaming_state) expect_bt_bap_stream_ops_disabled_called_once(stream); expect_bt_bap_stream_ops_released_not_called(); expect_bt_bap_stream_ops_disconnected_called_once(stream); - - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } static void test_cis_link_loss_in_disabling_state(struct ascs_test_suite_fixture *fixture, @@ -630,8 +478,6 @@ static void test_cis_link_loss_in_disabling_state(struct ascs_test_suite_fixture expect_bt_bap_stream_ops_disabled_not_called(); expect_bt_bap_stream_ops_released_not_called(); expect_bt_bap_stream_ops_disconnected_called_once(stream); - - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } ZTEST_F(ascs_test_suite, test_cis_link_loss_in_disabling_state_v1) @@ -690,8 +536,6 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state) /* Server-initiated disable operation that shall not cause transition to QoS */ expect_bt_bap_stream_ops_qos_set_not_called(); } - - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state_client_retries) @@ -741,8 +585,6 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state_client_retries) expect_bt_bap_stream_ops_connected_called_twice(stream); expect_bt_bap_stream_ops_started_called_once(stream); - - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } static struct bt_bap_stream *stream_allocated; @@ -823,6 +665,4 @@ ZTEST_F(ascs_test_suite, test_ase_state_notification_retry) k_sleep(K_MSEC(BT_CONN_INTERVAL_TO_MS(info.le.interval))); expect_bt_bap_stream_ops_configured_called_once(stream, EMPTY); - - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } diff --git a/tests/bluetooth/audio/ascs/src/test_ase_control_params.c b/tests/bluetooth/audio/ascs/src/test_ase_control_params.c index a4090da02e2..4f7d2a4c649 100644 --- a/tests/bluetooth/audio/ascs/src/test_ase_control_params.c +++ b/tests/bluetooth/audio/ascs/src/test_ase_control_params.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -80,12 +81,11 @@ static void test_ase_control_params_after(void *f) err = bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); zassert_equal(err, 0, "unexpected err response %d", err); + /* Sleep to trigger any pending state changes from unregister_cb */ + k_sleep(K_SECONDS(1)); + err = bt_bap_unicast_server_unregister(); - while (err != 0) { - zassert_equal(err, -EBUSY, "unexpected err response %d", err); - k_sleep(K_MSEC(10)); - err = bt_bap_unicast_server_unregister(); - } + zassert_equal(err, 0, "Unexpected err response %d", err); } static void test_ase_control_params_teardown(void *f) diff --git a/tests/bluetooth/audio/ascs/src/test_ase_register.c b/tests/bluetooth/audio/ascs/src/test_ase_register.c new file mode 100644 index 00000000000..b784d62a5b8 --- /dev/null +++ b/tests/bluetooth/audio/ascs/src/test_ase_register.c @@ -0,0 +1,163 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2024 Demant A/S + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "assert.h" +#include "bap_unicast_server.h" +#include "bap_unicast_server_expects.h" +#include "bap_stream.h" +#include "bap_stream_expects.h" +#include "conn.h" + +#include "test_common.h" + +static void ascs_register_test_suite_after(void *f) +{ + /* Attempt to clean up failing tests */ + (void)bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); + + /* Sleep to trigger any pending state changes */ + k_sleep(K_SECONDS(1)); + + (void)bt_bap_unicast_server_unregister(); +} + +ZTEST_SUITE(ascs_register_test_suite, NULL, NULL, NULL, ascs_register_test_suite_after, NULL); + +static ZTEST(ascs_register_test_suite, test_cb_register_without_ascs_registered) +{ + int err; + + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, -ENOTSUP, "Unexpected err response %d", err); +} + +static ZTEST(ascs_register_test_suite, test_ascs_register_with_null_param) +{ + int err; + + err = bt_bap_unicast_server_register(NULL); + zassert_equal(err, -EINVAL, "Unexpected err response %d", err); +} + +static ZTEST(ascs_register_test_suite, test_ascs_register_twice) +{ + int err; + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, + }; + + /* Setup already registered once, so calling once here should be sufficient */ + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, 0, "Unexpected err response %d", err); + + /* Setup already registered once, so calling once here should be sufficient */ + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, -EALREADY, "Unexpected err response %d", err); + + err = bt_bap_unicast_server_unregister(); + zassert_equal(err, 0, "Unexpected err response %d", err); +} + +static ZTEST(ascs_register_test_suite, test_ascs_register_too_many_sinks) +{ + int err; + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + 1, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, + }; + + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, -EINVAL, "Unexpected err response %d", err); +} + +static ZTEST(ascs_register_test_suite, test_ascs_register_too_many_sources) +{ + int err; + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1, + }; + + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, -EINVAL, "Unexpected err response %d", err); +} + +static ZTEST(ascs_register_test_suite, test_ascs_register_zero_ases) +{ + int err; + struct bt_bap_unicast_server_register_param param = {0, 0}; + + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, -EINVAL, "Unexpected err response %d", err); +} + +static ZTEST(ascs_register_test_suite, test_ascs_register_fewer_than_max_ases) +{ + int err; + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 ? CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT - 1 : 0, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 ? CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT - 1 : 0, + }; + + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, 0, "Unexpected err response %d", err); +} + +static ZTEST(ascs_register_test_suite, test_ascs_unregister_without_register) +{ + int err; + + err = bt_bap_unicast_server_unregister(); + zassert_equal(err, -EALREADY, "Unexpected err response %d", err); +} + +static ZTEST(ascs_register_test_suite, test_ascs_unregister_with_cbs_registered) +{ + struct bt_bap_unicast_server_register_param param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, + }; + int err; + + err = bt_bap_unicast_server_register(¶m); + zassert_equal(err, 0, "Unexpected err response %d", err); + + err = bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "Unexpected err response %d", err); + + /* Not valid to unregister while callbacks are still registered */ + err = bt_bap_unicast_server_unregister(); + zassert_equal(err, -EAGAIN, "Unexpected err response %d", err); + + err = bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); + zassert_equal(err, 0, "Unexpected err response %d", err); + + err = bt_bap_unicast_server_unregister(); + zassert_equal(err, 0, "Unexpected err response %d", err); +} diff --git a/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c b/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c index d91af834c52..763c5075f4e 100644 --- a/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c +++ b/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c @@ -8,12 +8,14 @@ */ #include +#include #include #include #include #include #include #include +#include #include "bap_unicast_server.h" #include "bap_unicast_server_expects.h" @@ -110,12 +112,11 @@ static void test_ase_state_transition_after(void *f) err = bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); zassert_equal(err, 0, "unexpected err response %d", err); + /* Sleep to trigger any pending state changes from unregister_cb */ + k_sleep(K_SECONDS(1)); + err = bt_bap_unicast_server_unregister(); - while (err != 0) { - zassert_equal(err, -EBUSY, "unexpected err response %d", err); - k_sleep(K_MSEC(10)); - err = bt_bap_unicast_server_unregister(); - } + zassert_equal(err, 0, "Unexpected err response %d", err); } static void test_ase_state_transition_teardown(void *f) diff --git a/tests/bluetooth/audio/ascs/src/test_ase_state_transition_invalid.c b/tests/bluetooth/audio/ascs/src/test_ase_state_transition_invalid.c index 454a3d85ac4..4bfb6ac6fe0 100644 --- a/tests/bluetooth/audio/ascs/src/test_ase_state_transition_invalid.c +++ b/tests/bluetooth/audio/ascs/src/test_ase_state_transition_invalid.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -75,12 +76,11 @@ static void test_ase_state_transition_invalid_after(void *f) err = bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); zassert_equal(err, 0, "unexpected err response %d", err); + /* Sleep to trigger any pending state changes from unregister_cb */ + k_sleep(K_SECONDS(1)); + err = bt_bap_unicast_server_unregister(); - while (err != 0) { - zassert_equal(err, -EBUSY, "unexpected err response %d", err); - k_sleep(K_MSEC(10)); - err = bt_bap_unicast_server_unregister(); - } + zassert_equal(err, 0, "Unexpected err response %d", err); } static void test_ase_state_transition_invalid_teardown(void *f) diff --git a/tests/bluetooth/audio/ascs/testcase.yaml b/tests/bluetooth/audio/ascs/testcase.yaml index 63663c81773..f0501d65cc8 100644 --- a/tests/bluetooth/audio/ascs/testcase.yaml +++ b/tests/bluetooth/audio/ascs/testcase.yaml @@ -16,6 +16,8 @@ tests: bluetooth.audio.ascs.test_unicast_client_enabled: type: unit extra_configs: + - CONFIG_BT_CENTRAL=y + - CONFIG_BT_ISO_CENTRAL=y - CONFIG_BT_BAP_UNICAST_CLIENT=y - CONFIG_BT_GATT_CLIENT=y - CONFIG_BT_GATT_AUTO_DISCOVER_CCC=y