Commit 79024574 authored by Andries Kruithof's avatar Andries Kruithof Committed by Anas Nashif
Browse files

Bluetooth: audio: test: Unittests for broadcast reception start



Implement unit tests for the broadcast reception start procedure,
both with proper and with improper parameters.

Signed-off-by: default avatarAndries Kruithof <andries.kruithof@nordicsemi.no>
parent b2d1e450
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -14,8 +14,10 @@ target_include_directories(testbinary PRIVATE include)
target_sources(testbinary
  PRIVATE
  ${ZEPHYR_BASE}/subsys/bluetooth/host/uuid.c
  ${ZEPHYR_BASE}/subsys/bluetooth/common/addr.c
  src/main.c
    src/test_common.c
    src/test_vcp.c
    src/test_micp.c
    src/test_broadcast_reception.c
)
+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ CONFIG_BT_CAP_COMMANDER=y
CONFIG_BT_BAP_BROADCAST_ASSISTANT=y
CONFIG_LOG=y
CONFIG_BT_CAP_COMMANDER_LOG_LEVEL_DBG=y

CONFIG_BT_BAP_BASS_MAX_SUBGROUPS=2
CONFIG_ASSERT=y
CONFIG_ASSERT_LEVEL=2
CONFIG_ASSERT_VERBOSE=y
+373 −0
Original line number Diff line number Diff line
/* test_broadcast_reception.c - unit test for broadcast reception */

/*
 * Copyright (c) 2024 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdlib.h>

#include <zephyr/bluetooth/audio/cap.h>
#include <zephyr/bluetooth/audio/vcp.h>
#include <zephyr/fff.h>

#include "bluetooth.h"
#include "cap_commander.h"
#include "conn.h"
#include "expects_util.h"
#include "cap_mocks.h"
#include "test_common.h"

#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(bt_broadcast_reception_test, CONFIG_BT_CAP_COMMANDER_LOG_LEVEL);

#define FFF_GLOBALS

#define SID          0x0E
#define ADV_INTERVAL 10
#define BROADCAST_ID 0x55AA55

struct cap_commander_test_broadcast_reception_fixture {
	struct bt_conn conns[CONFIG_BT_MAX_CONN];

	struct bt_bap_bass_subgroup start_subgroups[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS];
	struct bt_cap_commander_broadcast_reception_start_member_param
		start_member_params[CONFIG_BT_MAX_CONN];
	struct bt_cap_commander_broadcast_reception_start_param start_param;
};

static void test_start_param_init(void *f);

static void cap_commander_test_broadcast_reception_fixture_init(
	struct cap_commander_test_broadcast_reception_fixture *fixture)
{
	for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
		test_conn_init(&fixture->conns[i]);
	}
	test_start_param_init(fixture);
}

static void *cap_commander_test_broadcast_reception_setup(void)
{
	struct cap_commander_test_broadcast_reception_fixture *fixture;

	fixture = malloc(sizeof(*fixture));
	zassert_not_null(fixture);

	return fixture;
}

static void cap_commander_test_broadcast_reception_before(void *f)
{
	memset(f, 0, sizeof(struct cap_commander_test_broadcast_reception_fixture));
	cap_commander_test_broadcast_reception_fixture_init(f);
}

static void cap_commander_test_broadcast_reception_after(void *f)
{
	struct cap_commander_test_broadcast_reception_fixture *fixture = f;

	bt_cap_commander_unregister_cb(&mock_cap_commander_cb);

	for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
		mock_bt_conn_disconnected(&fixture->conns[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
	}
}

static void cap_commander_test_broadcast_reception_teardown(void *f)
{
	free(f);
}

static void test_start_param_init(void *f)
{
	struct cap_commander_test_broadcast_reception_fixture *fixture = f;
	int err;

	fixture->start_param.type = BT_CAP_SET_TYPE_AD_HOC;
	fixture->start_param.param = fixture->start_member_params;

	fixture->start_param.count = ARRAY_SIZE(fixture->start_member_params);

	for (size_t i = 0; i < ARRAY_SIZE(fixture->start_subgroups); i++) {
		fixture->start_subgroups[i].bis_sync = 1 << i;
		fixture->start_subgroups[i].metadata_len = 0;
	}

	for (size_t i = 0U; i < ARRAY_SIZE(fixture->start_member_params); i++) {
		fixture->start_member_params[i].member.member = &fixture->conns[i];
		bt_addr_le_copy(&fixture->start_member_params[i].addr, BT_ADDR_LE_ANY);
		fixture->start_member_params[i].adv_sid = SID;
		fixture->start_member_params[i].pa_interval = ADV_INTERVAL;
		fixture->start_member_params[i].broadcast_id = BROADCAST_ID;
		memcpy(fixture->start_member_params[i].subgroups, &fixture->start_subgroups[0],
		       sizeof(struct bt_bap_bass_subgroup) * CONFIG_BT_BAP_BASS_MAX_SUBGROUPS);
		fixture->start_member_params[i].num_subgroups = CONFIG_BT_BAP_BASS_MAX_SUBGROUPS;
	}

	for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
		err = bt_cap_commander_discover(&fixture->conns[i]);
		zassert_equal(0, err, "Unexpected return value %d", err);
	}

	for (size_t i = 0U; i < ARRAY_SIZE(fixture->start_member_params); i++) {
		fixture->start_member_params[i].member.member = &fixture->conns[i];
	}
}

ZTEST_SUITE(cap_commander_test_broadcast_reception, NULL,
	    cap_commander_test_broadcast_reception_setup,
	    cap_commander_test_broadcast_reception_before,
	    cap_commander_test_broadcast_reception_after,
	    cap_commander_test_broadcast_reception_teardown);

ZTEST_F(cap_commander_test_broadcast_reception, test_commander_reception_start)
{
	int err;

	err = bt_cap_commander_register_cb(&mock_cap_commander_cb);
	zassert_equal(0, err, "Unexpected return value %d", err);

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(0, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 1,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception, test_commander_reception_start_one_subgroup)
{
	int err;

	err = bt_cap_commander_register_cb(&mock_cap_commander_cb);
	zassert_equal(0, err, "Unexpected return value %d", err);

	/* We test with one subgroup, instead of CONFIG_BT_BAP_BASS_MAX_SUBGROUPS subgroups */
	for (size_t i = 0U; i < CONFIG_BT_MAX_CONN; i++) {
		fixture->start_param.param[i].num_subgroups = 1;
	}

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(0, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 1,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception, test_commander_reception_start_double)
{
	int err;

	err = bt_cap_commander_register_cb(&mock_cap_commander_cb);
	zassert_equal(0, err, "Unexpected return value %d", err);

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(0, err, "Unexpected return value %d", err);

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(0, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 2,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception, test_commander_reception_start_inval_param_null)
{
	int err;

	err = bt_cap_commander_broadcast_reception_start(NULL);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception,
	test_commander_reception_start_inval_param_zero_count)
{
	int err;

	fixture->start_param.count = 0;

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception,
	test_commander_reception_start_inval_param_high_count)
{
	int err;

	fixture->start_param.count = CONFIG_BT_MAX_CONN + 1;

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception,
	test_commander_reception_start_inval_param_null_param)
{
	int err;

	fixture->start_param.type = BT_CAP_SET_TYPE_AD_HOC;
	fixture->start_param.param = NULL;
	fixture->start_param.count = ARRAY_SIZE(fixture->conns);

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception, test_commander_reception_start_inval_null_member)
{
	int err;

	fixture->start_param.param[0].member.member = NULL;

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception, test_commander_reception_start_inval_missing_cas)
{
	int err;

	fixture->start_param.type = BT_CAP_SET_TYPE_CSIP;

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception, test_commander_reception_start_inval_addr_type)
{
	int err;

	fixture->start_param.param[0].addr.type = BT_ADDR_LE_RANDOM + 1;

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception, test_commander_reception_start_inval_sid)
{
	int err;

	fixture->start_param.param[0].adv_sid = BT_GAP_SID_MAX + 1;

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception,
	test_commander_reception_start_inval_pa_interval_low)
{
	int err;

	fixture->start_param.param[0].pa_interval = BT_GAP_PER_ADV_MIN_INTERVAL - 1;

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

/*
 * Test for pa_interval_high omitted
 * pa_interval is a uint16_t, BT_GAP_PER_ADV_MAX_INTERVAL is defined as 0xFFFF
 * and therefor we can not test in the current implementation
 */

ZTEST_F(cap_commander_test_broadcast_reception, test_commander_reception_start_inval_broadcast_id)
{
	int err;

	fixture->start_param.param[0].broadcast_id = BT_AUDIO_BROADCAST_ID_MAX + 1;

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception, test_commander_reception_start_inval_no_subgroups)
{
	int err;

	fixture->start_param.param[0].num_subgroups = 0;

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception, test_commander_reception_start_inval_num_subgroups)
{
	int err;

	fixture->start_param.param[0].num_subgroups = CONFIG_BT_BAP_BASS_MAX_SUBGROUPS + 1;

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception,
	test_commander_reception_start_inval_duplicate_bis_sync)
{
	int err;

	if (CONFIG_BT_BAP_BASS_MAX_SUBGROUPS == 1) {
		ztest_test_skip();
	}

	fixture->start_param.param[0].subgroups[0].bis_sync =
		fixture->start_param.param[0].subgroups[1].bis_sync;

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}

ZTEST_F(cap_commander_test_broadcast_reception, test_commander_reception_start_inval_metadata_len)
{
	int err;

	fixture->start_param.param[0].subgroups[0].metadata_len =
		CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE + 1;

	err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
	zassert_equal(-EINVAL, err, "Unexpected return value %d", err);

	zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 0,
			   mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
}
+1 −0
Original line number Diff line number Diff line
@@ -23,5 +23,6 @@ DECLARE_FAKE_VOID_FUNC(mock_cap_commander_volume_mute_changed_cb, struct bt_conn
DECLARE_FAKE_VOID_FUNC(mock_cap_commander_volume_offset_changed_cb, struct bt_conn *, int);
DECLARE_FAKE_VOID_FUNC(mock_cap_commander_microphone_mute_changed_cb, struct bt_conn *, int);
DECLARE_FAKE_VOID_FUNC(mock_cap_commander_microphone_gain_changed_cb, struct bt_conn *, int);
DECLARE_FAKE_VOID_FUNC(mock_cap_commander_broadcast_reception_start_cb, struct bt_conn *, int);

#endif /* MOCKS_CAP_COMMANDER_H_ */
+6 −1
Original line number Diff line number Diff line
@@ -15,7 +15,8 @@
	FAKE(mock_cap_commander_volume_mute_changed_cb)                                            \
	FAKE(mock_cap_commander_volume_offset_changed_cb)                                          \
	FAKE(mock_cap_commander_microphone_mute_changed_cb)                                        \
	FAKE(mock_cap_commander_microphone_gain_changed_cb)
	FAKE(mock_cap_commander_microphone_gain_changed_cb)                                        \
	FAKE(mock_cap_commander_broadcast_reception_start_cb)

DEFINE_FAKE_VOID_FUNC(mock_cap_commander_discovery_complete_cb, struct bt_conn *, int,
		      const struct bt_csip_set_coordinator_set_member *,
@@ -26,6 +27,7 @@ DEFINE_FAKE_VOID_FUNC(mock_cap_commander_volume_mute_changed_cb, struct bt_conn
DEFINE_FAKE_VOID_FUNC(mock_cap_commander_volume_offset_changed_cb, struct bt_conn *, int);
DEFINE_FAKE_VOID_FUNC(mock_cap_commander_microphone_mute_changed_cb, struct bt_conn *, int);
DEFINE_FAKE_VOID_FUNC(mock_cap_commander_microphone_gain_changed_cb, struct bt_conn *, int);
DEFINE_FAKE_VOID_FUNC(mock_cap_commander_broadcast_reception_start_cb, struct bt_conn *, int);

const struct bt_cap_commander_cb mock_cap_commander_cb = {
	.discovery_complete = mock_cap_commander_discovery_complete_cb,
@@ -42,6 +44,9 @@ const struct bt_cap_commander_cb mock_cap_commander_cb = {
	.microphone_gain_changed = mock_cap_commander_microphone_gain_changed_cb,
#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */
#endif /* CONFIG_BT_MICP_MIC_CTLR */
#if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT)
	.broadcast_reception_start = mock_cap_commander_broadcast_reception_start_cb,
#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
};

void mock_cap_commander_init(void)