Bluetooth: tests: bsim: host/adv/resume2

This test is an attempt at formalizing at least part of the behavior
described in commit 6a79c3deae.

Signed-off-by: Aleksander Wasaznik <aleksander.wasaznik@nordicsemi.no>
This commit is contained in:
Aleksander Wasaznik 2024-03-04 15:08:06 +01:00 committed by Fabio Baltieri
commit d4d84b0ac9
12 changed files with 493 additions and 0 deletions

View file

@ -12,6 +12,9 @@ source ${ZEPHYR_BASE}/tests/bsim/compile.source
app=tests/bsim/bluetooth/host/adv/resume compile app=tests/bsim/bluetooth/host/adv/resume compile
app=tests/bsim/bluetooth/host/adv/resume conf_file=prj_2.conf compile app=tests/bsim/bluetooth/host/adv/resume conf_file=prj_2.conf compile
app=tests/bsim/bluetooth/host/adv/resume2/connectable compile
app=tests/bsim/bluetooth/host/adv/resume2/connecter compile
app=tests/bsim/bluetooth/host/adv/resume2/dut compile
app=tests/bsim/bluetooth/host/adv/chain compile app=tests/bsim/bluetooth/host/adv/chain compile
app=tests/bsim/bluetooth/host/adv/extended conf_file=prj_advertiser.conf compile app=tests/bsim/bluetooth/host/adv/extended conf_file=prj_advertiser.conf compile
app=tests/bsim/bluetooth/host/adv/extended conf_file=prj_scanner.conf compile app=tests/bsim/bluetooth/host/adv/extended conf_file=prj_scanner.conf compile

View file

@ -0,0 +1,21 @@
# Copyright (c) 2024 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
project(app)
target_sources(app PRIVATE
main.c
)
zephyr_include_directories(
${BSIM_COMPONENTS_PATH}/libPhyComv1/src/
${BSIM_COMPONENTS_PATH}/libUtilv1/src/
)
add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib)
target_link_libraries(app PRIVATE
testlib
)

View file

@ -0,0 +1,47 @@
/* Copyright (c) 2024 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/sys/__assert.h>
#include <testlib/adv.h>
#include <testlib/conn.h>
/* @file
*
* This app advertises connectable with the name "connectable".
* It only receives one connection at a time. When the remote
* disconnects, it starts advertising again.
*
* This app is added to the simulation simply to be a target for
* a connection from the DUT.
*/
int main(void)
{
int err;
err = bt_enable(NULL);
__ASSERT_NO_MSG(!err);
err = bt_set_name("connectable");
__ASSERT_NO_MSG(!err);
while (true) {
struct bt_conn *conn = NULL;
bt_testlib_conn_wait_free();
err = bt_testlib_adv_conn(
&conn, BT_ID_DEFAULT,
(BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_FORCE_NAME_IN_AD));
__ASSERT_NO_MSG(!err);
bt_testlib_wait_disconnected(conn);
bt_testlib_conn_unref(&conn);
}
return 0;
}

View file

@ -0,0 +1,21 @@
CONFIG_TEST=y
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_ASSERT=y
CONFIG_BT_TESTING=y
CONFIG_LOG=y
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
CONFIG_BT_EXT_ADV=y
CONFIG_BT_PRIVACY=n
CONFIG_BT_SCAN_WITH_IDENTITY=n
CONFIG_BT_AUTO_PHY_UPDATE=n
CONFIG_BT_AUTO_DATA_LEN_UPDATE=n
CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n
CONFIG_BT_MAX_CONN=1
CONFIG_BT_ID_MAX=1

View file

@ -0,0 +1,21 @@
# Copyright (c) 2024 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
project(app)
target_sources(app PRIVATE
main.c
)
zephyr_include_directories(
${BSIM_COMPONENTS_PATH}/libPhyComv1/src/
${BSIM_COMPONENTS_PATH}/libUtilv1/src/
)
add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib)
target_link_libraries(app PRIVATE
testlib
)

View file

@ -0,0 +1,66 @@
/* Copyright (c) 2024 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/__assert.h>
#include <testlib/conn.h>
#include <testlib/scan.h>
LOG_MODULE_REGISTER(connecter, LOG_LEVEL_INF);
/* @file
*
* This app scans for a device with the name "dut" and connects
* to it. It then waits for the connection to be disconnected,
* before starting over.
*
* This app is added to the simulation simply to exercise the
* the DUT's connectable advertiser.
*
* Multiple instances of this app are added to the simulation,
* to exercise BT_MAX_CONN of the DUT.
*/
int main(void)
{
int err;
err = bt_enable(NULL);
__ASSERT_NO_MSG(!err);
while (true) {
bt_addr_le_t result;
struct bt_conn *conn = NULL;
bt_testlib_conn_wait_free();
err = bt_testlib_scan_find_name(&result, "dut");
__ASSERT_NO_MSG(!err);
/* The above scan will never timeout, but the below connect has
* a built-in timeout in the stack.
*
* The timeout causes `BT_HCI_ERR_UNKNOWN_CONN_ID`.
*
* The timeout is a good thing in this app. Maybe the DUT is
* going to change its address, so we should scan for the name
* again.
*/
err = bt_testlib_connect(&result, &conn);
if (err) {
__ASSERT_NO_MSG(err == BT_HCI_ERR_UNKNOWN_CONN_ID);
}
if (conn) {
bt_testlib_wait_disconnected(conn);
bt_testlib_conn_unref(&conn);
}
}
return 0;
}

View file

@ -0,0 +1,19 @@
CONFIG_TEST=y
CONFIG_BT=y
CONFIG_BT_CENTRAL=y
CONFIG_ASSERT=y
CONFIG_BT_TESTING=y
CONFIG_LOG=y
CONFIG_BT_EXT_ADV=n
CONFIG_BT_PRIVACY=n
CONFIG_BT_SCAN_WITH_IDENTITY=n
CONFIG_BT_AUTO_PHY_UPDATE=n
CONFIG_BT_AUTO_DATA_LEN_UPDATE=n
CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n
CONFIG_BT_MAX_CONN=1
CONFIG_BT_ID_MAX=1

View file

@ -0,0 +1,21 @@
# Copyright (c) 2024 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
project(app)
target_sources(app PRIVATE
main.c
)
zephyr_include_directories(
${BSIM_COMPONENTS_PATH}/libPhyComv1/src/
${BSIM_COMPONENTS_PATH}/libUtilv1/src/
)
add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib)
target_link_libraries(app PRIVATE
testlib
)

View file

@ -0,0 +1,200 @@
/* Copyright (c) 2024 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/sys/atomic_builtin.h>
#include <zephyr/sys/atomic_types.h>
#include <testlib/conn.h>
#include <testlib/scan.h>
#include <bs_tracing.h>
#include <bstests.h>
extern enum bst_result_t bst_result;
LOG_MODULE_REGISTER(dut, LOG_LEVEL_INF);
atomic_t connected_count;
static void on_connected(struct bt_conn *conn, uint8_t conn_err)
{
atomic_t count = atomic_inc(&connected_count) + 1;
LOG_INF("Connected. Current count %d", count);
}
static void on_disconnected(struct bt_conn *conn, uint8_t reason)
{
atomic_t count = atomic_dec(&connected_count) - 1;
LOG_INF("Disconnected. Current count %d", count);
}
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = on_connected,
.disconnected = on_disconnected,
};
static void disconnect_all(void)
{
for (size_t i = 0; i < CONFIG_BT_MAX_CONN; i++) {
int err;
struct bt_conn *conn = bt_testlib_conn_unindex(BT_CONN_TYPE_LE, i);
if (conn) {
err = bt_testlib_disconnect(&conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
__ASSERT_NO_MSG(!err);
}
}
}
int main(void)
{
int err;
bt_addr_le_t connectable_addr;
struct bt_conn *conn = NULL;
bst_result = In_progress;
err = bt_enable(NULL);
__ASSERT_NO_MSG(!err);
err = bt_set_name("dut");
__ASSERT_NO_MSG(!err);
LOG_INF("---------- Test setup ----------");
LOG_INF("Environment test: Advertiser fills connection capacity.");
/* `bt_le_adv_start` is invoked once, and.. */
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME_AD, NULL, 0, NULL, 0);
__ASSERT_NO_MSG(!err);
/* .. the advertiser shall autoresume. Since it's not
* stopped, it shall continue receivng connections until
* the stack runs out of connection objects.
*/
LOG_INF("Waiting for connections...");
while (atomic_get(&connected_count) < CONFIG_BT_MAX_CONN) {
k_msleep(1000);
}
LOG_INF("Environment test done");
LOG_INF("Environment test: Disconnect one to see that it comes back");
/* Disconnect one of the connections. It does matter
* which, but object with index 0 is chosen for
* simplicity.
*/
conn = bt_testlib_conn_unindex(BT_CONN_TYPE_LE, 0);
__ASSERT_NO_MSG(conn);
/* Disconnect, but wait with calling unref.. */
err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
__ASSERT_NO_MSG(!err);
bt_testlib_wait_disconnected(conn);
/* Simulate a delayed unref. We delay to make sure the resume is not
* triggered by disconnection, but by a connection object becoming
* available.
*/
k_sleep(K_SECONDS(10));
bt_testlib_conn_unref(&conn);
/* Since there is a free connection object again, the
* advertiser shall automatically resume and receive a
* new connection.
*/
LOG_INF("Waiting for connections...");
while (atomic_get(&connected_count) < CONFIG_BT_MAX_CONN) {
k_msleep(1000);
}
LOG_INF("Environment test done");
LOG_INF("Clean up");
err = bt_le_adv_stop();
__ASSERT_NO_MSG(!err);
disconnect_all();
LOG_INF("Cleanup done");
LOG_INF("Setup step: Connect one central connection");
err = bt_testlib_scan_find_name(&connectable_addr, "connectable");
__ASSERT_NO_MSG(!err);
err = bt_testlib_connect(&connectable_addr, &conn);
__ASSERT_NO_MSG(!err);
LOG_INF("Setup step done");
LOG_INF("Setup step: Start advertiser. Let it fill the connection limit.");
/* With one connection slot taken by the central role, we fill the rest. */
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME_AD, NULL, 0, NULL, 0);
__ASSERT_NO_MSG(!err);
LOG_INF("Waiting for connections...");
while (atomic_get(&connected_count) < CONFIG_BT_MAX_CONN) {
k_sleep(K_SECONDS(1));
}
LOG_INF("Setup step done");
LOG_INF("---------- Test start ----------");
LOG_INF("Disconnect, wait and connect the central connection.");
/* In this situation, disconnecting the central role should not allow
* the advertiser to resume. This behavior was introduced in 6a79c3deae.
*/
LOG_INF("Poke: Disconnect");
err = bt_testlib_disconnect(&conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
__ASSERT_NO_MSG(!err);
LOG_INF("Poke: Wait to bait the advertiser");
k_sleep(K_SECONDS(5));
LOG_INF("Observe: Connect");
err = bt_testlib_connect(&connectable_addr, &conn);
if (err) {
/* If the test fails, it's because the advertiser 'stole' the
* central's connection slot.
*/
__ASSERT_NO_MSG(err == -ENOMEM);
LOG_ERR("Fault: Advertiser stole the connection slot");
bs_trace_silent_exit(1);
}
bst_result = Passed;
LOG_INF("Test passed");
bs_trace_silent_exit(0);
return 0;
}

View file

@ -0,0 +1,22 @@
CONFIG_TEST=y
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
CONFIG_ASSERT=y
CONFIG_BT_TESTING=y
CONFIG_LOG=y
CONFIG_BT_EXT_ADV=n
CONFIG_BT_PRIVACY=n
CONFIG_BT_SCAN_WITH_IDENTITY=n
CONFIG_BT_AUTO_PHY_UPDATE=n
CONFIG_BT_AUTO_DATA_LEN_UPDATE=n
CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n
CONFIG_BT_MAX_CONN=3
CONFIG_BT_ID_MAX=1

View file

@ -0,0 +1,16 @@
#!/usr/bin/env bash
# Copyright (c) 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
set -eu
: "${ZEPHYR_BASE:?ZEPHYR_BASE must be defined}"
INCR_BUILD=1
source ${ZEPHYR_BASE}/tests/bsim/compile.source
app="$(guess_test_relpath)"/connectable compile
app="$(guess_test_relpath)"/connecter compile
app="$(guess_test_relpath)"/dut compile
wait_for_background_jobs

View file

@ -0,0 +1,36 @@
#!/usr/bin/env bash
# Copyright (c) 2024 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
set -eu
source ${ZEPHYR_BASE}/tests/bsim/sh_common.source
verbosity_level=2
simulation_id="resume2"
dut_exe="${BSIM_OUT_PATH}/bin/bs_${BOARD_TS}_$(guess_test_long_name)_dut_prj_conf"
connecter_exe="${BSIM_OUT_PATH}/bin/bs_${BOARD_TS}_$(guess_test_long_name)_connecter_prj_conf"
connectable_exe="${BSIM_OUT_PATH}/bin/bs_${BOARD_TS}_$(guess_test_long_name)_connectable_prj_conf"
cd ${BSIM_OUT_PATH}/bin
Execute "$dut_exe" \
-v=${verbosity_level} -s="${simulation_id}" -d=0 -RealEncryption=1
Execute "$connecter_exe" \
-v=${verbosity_level} -s="${simulation_id}" -d=1 -RealEncryption=1
Execute "$connecter_exe" \
-v=${verbosity_level} -s="${simulation_id}" -d=2 -RealEncryption=1
Execute "$connecter_exe" \
-v=${verbosity_level} -s="${simulation_id}" -d=3 -RealEncryption=1
Execute "$connectable_exe" \
-v=${verbosity_level} -s="${simulation_id}" -d=4 -RealEncryption=1
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s="${simulation_id}" \
-D=5 -sim_length=60e6 $@
wait_for_background_jobs