From f6712c43d4ed5d5f74332904170038b18bcb33dd Mon Sep 17 00:00:00 2001 From: Rubin Gerritsen Date: Wed, 11 Sep 2024 14:06:11 +0200 Subject: [PATCH] tests: Bluetooth: Add some more tests for bt_le_create_conn() Adds coverage for attempting to connect while already connecting or connecting to a device that already exists. Signed-off-by: Rubin Gerritsen --- tests/bsim/bluetooth/host/central/prj.conf | 1 + .../host/central/src/dummy_peripheral.c | 66 ++++++++ tests/bsim/bluetooth/host/central/src/main.c | 143 ++++++++++++++++-- .../run_central_connect_to_existing.sh | 21 +++ .../run_central_connect_when_connecting.sh | 18 +++ 5 files changed, 238 insertions(+), 11 deletions(-) create mode 100644 tests/bsim/bluetooth/host/central/src/dummy_peripheral.c create mode 100755 tests/bsim/bluetooth/host/central/tests_scripts/run_central_connect_to_existing.sh create mode 100755 tests/bsim/bluetooth/host/central/tests_scripts/run_central_connect_when_connecting.sh diff --git a/tests/bsim/bluetooth/host/central/prj.conf b/tests/bsim/bluetooth/host/central/prj.conf index 1f446a5bb273aa..684f25ff94554a 100644 --- a/tests/bsim/bluetooth/host/central/prj.conf +++ b/tests/bsim/bluetooth/host/central/prj.conf @@ -1,3 +1,4 @@ CONFIG_ASSERT=y CONFIG_BT=y CONFIG_BT_CENTRAL=y +CONFIG_BT_PERIPHERAL=y diff --git a/tests/bsim/bluetooth/host/central/src/dummy_peripheral.c b/tests/bsim/bluetooth/host/central/src/dummy_peripheral.c new file mode 100644 index 00000000000000..e7a85a80e658b9 --- /dev/null +++ b/tests/bsim/bluetooth/host/central/src/dummy_peripheral.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bstests.h" +#include "babblekit/testcase.h" +#include + +static K_SEM_DEFINE(sem_connected, 0, 1); + +static void connected_cb(struct bt_conn *conn, uint8_t err) +{ + TEST_ASSERT(conn); + TEST_ASSERT(err == 0, "Expected success"); + + k_sem_give(&sem_connected); + bt_conn_unref(conn); +} + +static struct bt_conn_cb conn_cb = { + .connected = connected_cb, +}; + +static void test_peripheral_dummy(void) +{ + int err; + const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR))}; + + bt_conn_cb_register(&conn_cb); + + bt_addr_le_t addr = {.type = BT_ADDR_LE_RANDOM, + .a.val = {0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}}; + + err = bt_id_create(&addr, NULL); + TEST_ASSERT(err == 0, "Failed to create iD (err %d)", err); + + /* Initialize Bluetooth */ + err = bt_enable(NULL); + TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err); + + err = bt_le_adv_start(BT_LE_ADV_CONN_ONE_TIME, ad, ARRAY_SIZE(ad), NULL, 0); + TEST_ASSERT(err == 0, "Advertising failed to start (err %d)", err); + + err = k_sem_take(&sem_connected, K_FOREVER); + TEST_ASSERT(err == 0, "Failed getting connected timeout", err); + + TEST_PASS("Passed"); +} + +static const struct bst_test_instance test_def[] = { + { + .test_id = "peripheral_dummy", + .test_descr = "Connectable peripheral", + .test_tick_f = bst_tick, + .test_main_f = test_peripheral_dummy, + }, + BSTEST_END_MARKER, +}; + +struct bst_test_list *test_peripheral_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_def); +} diff --git a/tests/bsim/bluetooth/host/central/src/main.c b/tests/bsim/bluetooth/host/central/src/main.c index 2e66f4179828ba..2068ecefc8d8ff 100644 --- a/tests/bsim/bluetooth/host/central/src/main.c +++ b/tests/bsim/bluetooth/host/central/src/main.c @@ -8,17 +8,36 @@ #include "babblekit/testcase.h" #include +/* Include conn_internal for the purpose of checking reference counts. */ +#include "host/conn_internal.h" + +struct bst_test_list *test_peripheral_install(struct bst_test_list *tests); + +static K_SEM_DEFINE(sem_failed_to_connect, 0, 1); static K_SEM_DEFINE(sem_connected, 0, 1); -static void connected_cb(struct bt_conn *conn, uint8_t err) +static void connected_cb_expect_fail(struct bt_conn *conn, uint8_t err) { TEST_ASSERT(conn); TEST_ASSERT(err == BT_HCI_ERR_UNKNOWN_CONN_ID, "Expected connection timeout"); + k_sem_give(&sem_failed_to_connect); + bt_conn_unref(conn); +} + +static void connected_cb(struct bt_conn *conn, uint8_t err) +{ + TEST_ASSERT(conn); + TEST_ASSERT(err == BT_HCI_ERR_SUCCESS, "Expected connection establishment"); + k_sem_give(&sem_connected); bt_conn_unref(conn); } +static struct bt_conn_cb conn_cb_expect_fail = { + .connected = connected_cb_expect_fail, +}; + static struct bt_conn_cb conn_cb = { .connected = connected_cb, }; @@ -44,14 +63,14 @@ static void test_central_connect_timeout_with_timeout(uint32_t timeout_ms) .timeout = timeout_ms / 10, }; - k_sem_reset(&sem_connected); + k_sem_reset(&sem_failed_to_connect); const uint64_t conn_create_start = k_uptime_get(); err = bt_conn_le_create(&peer, &create_param, BT_LE_CONN_PARAM_DEFAULT, &conn); TEST_ASSERT(err == 0, "Failed starting initiator (err %d)", err); - err = k_sem_take(&sem_connected, K_MSEC(2 * expected_conn_timeout_ms)); + err = k_sem_take(&sem_failed_to_connect, K_MSEC(2 * expected_conn_timeout_ms)); TEST_ASSERT(err == 0, "Failed getting connected timeout within %d s (err %d)", 2 * expected_conn_timeout_ms, err); @@ -63,14 +82,15 @@ static void test_central_connect_timeout_with_timeout(uint32_t timeout_ms) TEST_PRINT("Connection timeout after %d ms", time_diff_ms); TEST_ASSERT(diff_to_expected_ms < 0.1 * expected_conn_timeout_ms, "Connection timeout not within 10%% of expected timeout. " - "Actual timeout: %d", time_diff_ms); + "Actual timeout: %d", + time_diff_ms); } static void test_central_connect_timeout(void) { int err; - bt_conn_cb_register(&conn_cb); + bt_conn_cb_register(&conn_cb_expect_fail); /* Initialize Bluetooth */ err = bt_enable(NULL); @@ -82,14 +102,118 @@ static void test_central_connect_timeout(void) TEST_PASS("Correct timeout"); } +static void test_central_connect_when_connecting(void) +{ + int err; + + bt_conn_cb_register(&conn_cb_expect_fail); + + /* Initialize Bluetooth */ + err = bt_enable(NULL); + TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err); + + struct bt_conn *conn; + + bt_addr_le_t peer = {.a.val = {0x01}}; + + const struct bt_conn_le_create_param create_param = { + .options = BT_CONN_LE_OPT_NONE, + .interval = BT_GAP_SCAN_FAST_INTERVAL, + .window = BT_GAP_SCAN_FAST_WINDOW, + }; + + k_sem_reset(&sem_failed_to_connect); + + err = bt_conn_le_create(&peer, &create_param, BT_LE_CONN_PARAM_DEFAULT, &conn); + TEST_ASSERT(err == 0, "Failed starting initiator (err %d)", err); + + /* Now we have a valid connection reference */ + atomic_val_t initial_refs = atomic_get(&conn->ref); + + TEST_ASSERT(initial_refs >= 1, "Expect to have at least once reference"); + + err = bt_conn_le_create(&peer, &create_param, BT_LE_CONN_PARAM_DEFAULT, &conn); + TEST_ASSERT(err == -EALREADY, "Expected to fail to create connection (err %d)", err); + + /* Expect the number of refs to be unchanged. */ + TEST_ASSERT(atomic_get(&conn->ref) == initial_refs, + "Expect number of references to be unchanged"); + + err = k_sem_take(&sem_failed_to_connect, K_FOREVER); + TEST_ASSERT(err == 0, "Failed getting connected timeout", err); + + TEST_ASSERT(atomic_get(&conn->ref) == 0, "Expect no more references"); + + TEST_PASS("Passed"); +} + +static void test_central_connect_to_existing(void) +{ + int err; + + bt_conn_cb_register(&conn_cb); + + /* Initialize Bluetooth */ + err = bt_enable(NULL); + TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err); + + struct bt_conn *conn; + + bt_addr_le_t peer = {.type = BT_ADDR_LE_RANDOM, + .a.val = {0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}}; + + const struct bt_conn_le_create_param create_param = { + .options = BT_CONN_LE_OPT_NONE, + .interval = BT_GAP_SCAN_FAST_INTERVAL, + .window = BT_GAP_SCAN_FAST_WINDOW, + }; + + k_sem_reset(&sem_connected); + + err = bt_conn_le_create(&peer, &create_param, BT_LE_CONN_PARAM_DEFAULT, &conn); + TEST_ASSERT(err == 0, "Failed starting initiator (err %d)", err); + + err = k_sem_take(&sem_connected, K_FOREVER); + TEST_ASSERT(err == 0, "Failed establishing connection", err); + + /* Now we have a valid connection reference */ + atomic_val_t initial_refs = atomic_get(&conn->ref); + + TEST_ASSERT(initial_refs >= 1, "Expect to have at least once reference"); + + err = bt_conn_le_create(&peer, &create_param, BT_LE_CONN_PARAM_DEFAULT, &conn); + TEST_ASSERT(err == -EINVAL, "Expected to fail to create a connection (err %d)", err); + + /* Expect the number of refs to be unchanged. */ + TEST_ASSERT(atomic_get(&conn->ref) == initial_refs, + "Expect number of references to be unchanged"); + + TEST_PASS("Passed"); +} + static const struct bst_test_instance test_def[] = { { .test_id = "central_connect_timeout", .test_descr = "Verifies that the default connection timeout is used correctly", .test_tick_f = bst_tick, - .test_main_f = test_central_connect_timeout + .test_main_f = test_central_connect_timeout, + }, + { + .test_id = "central_connect_when_connecting", + .test_descr = "Verifies that the stack returns an error code when trying to connect" + " while already connecting", + .test_tick_f = bst_tick, + .test_main_f = test_central_connect_when_connecting, }, - BSTEST_END_MARKER + { + .test_id = "central_connect_to_existing", + .test_descr = + "Verifies that the stack returns an error code when trying to connect" + " to an existing device and does not unref the existing connection object.", + .test_tick_f = bst_tick, + .test_main_f = test_central_connect_to_existing, + }, + BSTEST_END_MARKER, }; static struct bst_test_list *test_central_install(struct bst_test_list *tests) @@ -97,10 +221,7 @@ static struct bst_test_list *test_central_install(struct bst_test_list *tests) return bst_add_tests(tests, test_def); } -bst_test_install_t test_installers[] = { - test_central_install, - NULL -}; +bst_test_install_t test_installers[] = {test_central_install, test_peripheral_install, NULL}; int main(void) { diff --git a/tests/bsim/bluetooth/host/central/tests_scripts/run_central_connect_to_existing.sh b/tests/bsim/bluetooth/host/central/tests_scripts/run_central_connect_to_existing.sh new file mode 100755 index 00000000000000..af64f6a14ad10d --- /dev/null +++ b/tests/bsim/bluetooth/host/central/tests_scripts/run_central_connect_to_existing.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="central_connect_timeout_to_existing" +verbosity_level=2 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_central_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central_connect_to_existing + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_central_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral_dummy + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=60e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/central/tests_scripts/run_central_connect_when_connecting.sh b/tests/bsim/bluetooth/host/central/tests_scripts/run_central_connect_when_connecting.sh new file mode 100755 index 00000000000000..5d352adc0fe167 --- /dev/null +++ b/tests/bsim/bluetooth/host/central/tests_scripts/run_central_connect_when_connecting.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="central_connect_when_connecting" +verbosity_level=2 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_central_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central_connect_when_connecting + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=1 -sim_length=60e6 $@ + +wait_for_background_jobs