diff --git a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/prj.conf b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/prj.conf index 2496e735b86..b7089ee2a5d 100644 --- a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/prj.conf +++ b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/prj.conf @@ -10,6 +10,7 @@ CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y CONFIG_BT_L2CAP_ECRED=y CONFIG_BT_EATT=y CONFIG_BT_EATT_MAX=1 +CONFIG_BT_EATT_AUTO_CONNECT=n CONFIG_ASSERT=y CONFIG_BT_TESTING=y diff --git a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/src/common.h b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/src/common.h index ab72a71bd70..2c28ad9f18a 100644 --- a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/src/common.h +++ b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/src/common.h @@ -27,7 +27,7 @@ extern enum bst_result_t bst_result; -#define WAIT_TIME (30 * 1e6) /*seconds*/ +#define WAIT_TIME (60 * 1e6) /*seconds*/ #define CREATE_FLAG(flag) static atomic_t flag = (atomic_t)false #define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)true) diff --git a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/src/gatt_client_test.c b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/src/gatt_client_test.c index 9a660e17fea..8c6fba7a240 100644 --- a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/src/gatt_client_test.c +++ b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/src/gatt_client_test.c @@ -176,12 +176,7 @@ static void gatt_discover(const struct bt_uuid *uuid, uint8_t type) WAIT_FOR_FLAG(flag_discover_complete); printk("Discover complete\n"); } - -static uint8_t gatt_read_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params, - const void *data, uint16_t length); - static struct bt_gatt_read_params chan_1_read = { - .func = gatt_read_cb, .handle_count = 1, .single = { .handle = 0, /* Will be set later */ @@ -189,7 +184,6 @@ static struct bt_gatt_read_params chan_1_read = { }, }; static struct bt_gatt_read_params chan_2_read = { - .func = gatt_read_cb, .handle_count = 1, .single = { .handle = 0, /* Will be set later */ @@ -197,7 +191,6 @@ static struct bt_gatt_read_params chan_2_read = { }, }; static struct bt_gatt_read_params db_hash_read = { - .func = gatt_read_cb, .handle_count = 0, .by_uuid = { .start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE, @@ -213,29 +206,54 @@ void expect_status(uint8_t err, uint8_t status) } } -static uint8_t gatt_read_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params, - const void *data, uint16_t length) +static uint8_t gatt_read_expect_success_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, const void *data, + uint16_t length) { printk("GATT read cb: err 0x%02X\n", err); + expect_status(err, BT_ATT_ERR_SUCCESS); if (params == &db_hash_read) { - expect_status(err, BT_ATT_ERR_SUCCESS); SET_FLAG(flag_db_hash_read); } else if (params == &chan_1_read) { - if (flag_db_hash_read) { - expect_status(err, BT_ATT_ERR_SUCCESS); - } else { - expect_status(err, BT_ATT_ERR_DB_OUT_OF_SYNC); - } - SET_FLAG(flag_chan_1_read); } else if (params == &chan_2_read) { - if (flag_db_hash_read) { - expect_status(err, BT_ATT_ERR_SUCCESS); - } else { - expect_status(err, BT_ATT_ERR_DB_OUT_OF_SYNC); - } + SET_FLAG(flag_chan_2_read); + } else { + FAIL("Unexpected params\n"); + } + return 0; +} + +static uint8_t gatt_read_expect_err_unlikely_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) +{ + printk("GATT read cb: err 0x%02X\n", err); + expect_status(err, BT_ATT_ERR_UNLIKELY); + + if (params == &chan_1_read) { + SET_FLAG(flag_chan_1_read); + } else if (params == &chan_2_read) { + SET_FLAG(flag_chan_2_read); + } else { + FAIL("Unexpected params\n"); + } + + return 0; +} + +static uint8_t gatt_read_expect_err_out_of_sync_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) +{ + printk("GATT read cb: err 0x%02X\n", err); + expect_status(err, BT_ATT_ERR_DB_OUT_OF_SYNC); + + if (params == &chan_1_read) { + SET_FLAG(flag_chan_1_read); + } else if (params == &chan_2_read) { SET_FLAG(flag_chan_2_read); } else { FAIL("Unexpected params\n"); @@ -294,7 +312,7 @@ static void enable_robust_caching(void) printk("Success\n"); } -static void test_main(void) +static void test_main_common(bool connect_eatt) { int err; @@ -326,9 +344,11 @@ static void test_main(void) enable_robust_caching(); - while (bt_eatt_count(g_conn) < 1) { - /* Wait for EATT channel to connect, in case it hasn't already */ - k_sleep(K_MSEC(10)); + if (connect_eatt) { + while (bt_eatt_count(g_conn) < 1) { + /* Wait for EATT channel to connect, in case it hasn't already */ + k_sleep(K_MSEC(10)); + } } /* Tell the server to register additional service */ @@ -339,7 +359,39 @@ static void test_main(void) chan_1_read.single.handle = chrc_handle; chan_2_read.single.handle = chrc_handle; +} +static void test_main_db_hash_read_eatt(void) +{ + test_main_common(true); + + /* Read the DB hash to become change-aware */ + db_hash_read.func = gatt_read_expect_success_cb; + gatt_read(&db_hash_read); + WAIT_FOR_FLAG(flag_db_hash_read); + + /* These shall now succeed */ + chan_1_read.func = gatt_read_expect_success_cb; + chan_2_read.func = gatt_read_expect_success_cb; + UNSET_FLAG(flag_chan_1_read); + UNSET_FLAG(flag_chan_2_read); + gatt_read(&chan_1_read); + gatt_read(&chan_2_read); + WAIT_FOR_FLAG(flag_chan_1_read); + WAIT_FOR_FLAG(flag_chan_2_read); + + /* Signal to server that reads are done */ + backchannel_sync_send(); + + PASS("GATT client Passed\n"); +} + +static void test_main_out_of_sync_eatt(void) +{ + test_main_common(true); + + chan_1_read.func = gatt_read_expect_err_out_of_sync_cb; + chan_2_read.func = gatt_read_expect_err_out_of_sync_cb; gatt_read(&chan_1_read); gatt_read(&chan_2_read); @@ -350,9 +402,14 @@ static void test_main(void) WAIT_FOR_FLAG(flag_chan_1_read); WAIT_FOR_FLAG(flag_chan_2_read); + /* Read the DB hash to become change-aware */ + db_hash_read.func = gatt_read_expect_success_cb; gatt_read(&db_hash_read); WAIT_FOR_FLAG(flag_db_hash_read); + /* These shall now succeed */ + chan_1_read.func = gatt_read_expect_success_cb; + chan_2_read.func = gatt_read_expect_success_cb; UNSET_FLAG(flag_chan_1_read); UNSET_FLAG(flag_chan_2_read); gatt_read(&chan_1_read); @@ -360,15 +417,146 @@ static void test_main(void) WAIT_FOR_FLAG(flag_chan_1_read); WAIT_FOR_FLAG(flag_chan_2_read); + /* Signal to server that reads are done */ + backchannel_sync_send(); + + PASS("GATT client Passed\n"); +} + +static void test_main_retry_reads_eatt(void) +{ + test_main_common(true); + + chan_1_read.func = gatt_read_expect_err_out_of_sync_cb; + chan_2_read.func = gatt_read_expect_err_out_of_sync_cb; + gatt_read(&chan_1_read); + gatt_read(&chan_2_read); + + /* Wait until received response on both reads. When robust caching is implemented + * on the client side, the waiting shall be done automatically by the host when + * reading the DB hash. + */ + WAIT_FOR_FLAG(flag_chan_1_read); + WAIT_FOR_FLAG(flag_chan_2_read); + + /* Retry the reads, these shall time out */ + chan_1_read.func = gatt_read_expect_err_unlikely_cb; + chan_2_read.func = gatt_read_expect_err_unlikely_cb; + UNSET_FLAG(flag_chan_1_read); + UNSET_FLAG(flag_chan_2_read); + gatt_read(&chan_1_read); + gatt_read(&chan_2_read); + WAIT_FOR_FLAG(flag_chan_1_read); + WAIT_FOR_FLAG(flag_chan_2_read); + + /* Signal to server that reads are done */ + backchannel_sync_send(); + + PASS("GATT client Passed\n"); +} + +static void test_main_db_hash_read_no_eatt(void) +{ + test_main_common(false); + + /* Read the DB hash to become change-aware */ + db_hash_read.func = gatt_read_expect_success_cb; + gatt_read(&db_hash_read); + WAIT_FOR_FLAG(flag_db_hash_read); + + /* Read shall now succeed */ + chan_1_read.func = gatt_read_expect_success_cb; + UNSET_FLAG(flag_chan_1_read); + gatt_read(&chan_1_read); + WAIT_FOR_FLAG(flag_chan_1_read); + + /* Signal to server that reads are done */ + backchannel_sync_send(); + + PASS("GATT client Passed\n"); +} + +static void test_main_out_of_sync_no_eatt(void) +{ + test_main_common(false); + + chan_1_read.func = gatt_read_expect_err_out_of_sync_cb; + gatt_read(&chan_1_read); + WAIT_FOR_FLAG(flag_chan_1_read); + + /* Read the DB hash to become change-aware */ + db_hash_read.func = gatt_read_expect_success_cb; + gatt_read(&db_hash_read); + WAIT_FOR_FLAG(flag_db_hash_read); + + /* Read shall now succeed */ + chan_1_read.func = gatt_read_expect_success_cb; + UNSET_FLAG(flag_chan_1_read); + gatt_read(&chan_1_read); + WAIT_FOR_FLAG(flag_chan_1_read); + + /* Signal to server that reads are done */ + backchannel_sync_send(); + + PASS("GATT client Passed\n"); +} + +static void test_main_retry_reads_no_eatt(void) +{ + test_main_common(false); + + chan_1_read.func = gatt_read_expect_err_out_of_sync_cb; + gatt_read(&chan_1_read); + WAIT_FOR_FLAG(flag_chan_1_read); + + /* Read again to become change-aware */ + chan_1_read.func = gatt_read_expect_success_cb; + UNSET_FLAG(flag_chan_1_read); + gatt_read(&chan_1_read); + WAIT_FOR_FLAG(flag_chan_1_read); + + /* Signal to server that reads are done */ + backchannel_sync_send(); + PASS("GATT client Passed\n"); } static const struct bst_test_instance test_vcs[] = { { - .test_id = "gatt_client", + .test_id = "gatt_client_db_hash_read_eatt", .test_post_init_f = test_init, .test_tick_f = test_tick, - .test_main_f = test_main, + .test_main_f = test_main_db_hash_read_eatt, + }, + { + .test_id = "gatt_client_out_of_sync_eatt", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main_out_of_sync_eatt, + }, + { + .test_id = "gatt_client_retry_reads_eatt", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main_retry_reads_eatt, + }, + { + .test_id = "gatt_client_db_hash_read_no_eatt", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main_db_hash_read_no_eatt, + }, + { + .test_id = "gatt_client_out_of_sync_no_eatt", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main_out_of_sync_no_eatt, + }, + { + .test_id = "gatt_client_retry_reads_no_eatt", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main_retry_reads_no_eatt, }, BSTEST_END_MARKER, }; diff --git a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/src/gatt_server_test.c b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/src/gatt_server_test.c index eb60229fd7f..e8866446f0c 100644 --- a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/src/gatt_server_test.c +++ b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/src/gatt_server_test.c @@ -9,7 +9,6 @@ extern enum bst_result_t bst_result; CREATE_FLAG(flag_is_connected); -CREATE_FLAG(flag_read_done); static struct bt_conn *g_conn; @@ -61,7 +60,6 @@ static ssize_t read_test_chrc(struct bt_conn *conn, const struct bt_gatt_attr *a uint16_t len, uint16_t offset) { printk("Characteristic read\n"); - SET_FLAG(flag_read_done); return bt_gatt_attr_read(conn, attr, buf, len, offset, (const void *)chrc_data, CHRC_SIZE); } @@ -76,7 +74,7 @@ static struct bt_gatt_attr additional_attributes[] = { static struct bt_gatt_service additional_gatt_service = BT_GATT_SERVICE(additional_attributes); -static void test_main(void) +static void test_main_common(bool connect_eatt) { int err; const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, @@ -104,6 +102,15 @@ static void test_main(void) WAIT_FOR_FLAG(flag_is_connected); + if (connect_eatt) { + err = bt_eatt_connect(g_conn, CONFIG_BT_EATT_MAX); + if (err) { + FAIL("Failed to connect EATT channels (err %d)\n", err); + + return; + } + } + /* Wait for client to do discovery and configuration */ backchannel_sync_wait(); @@ -116,17 +123,34 @@ static void test_main(void) /* Signal to client that additional service is registered */ backchannel_sync_send(); - WAIT_FOR_FLAG(flag_read_done); + /* Wait for client to be done reading */ + backchannel_sync_wait(); PASS("GATT server passed\n"); } +static void test_main_eatt(void) +{ + test_main_common(true); +} + +static void test_main_no_eatt(void) +{ + test_main_common(false); +} + static const struct bst_test_instance test_gatt_server[] = { { - .test_id = "gatt_server", + .test_id = "gatt_server_eatt", .test_post_init_f = test_init, .test_tick_f = test_tick, - .test_main_f = test_main, + .test_main_f = test_main_eatt, + }, + { + .test_id = "gatt_server_no_eatt", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main_no_eatt, }, BSTEST_END_MARKER, }; diff --git a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt.sh b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/_run_test.sh similarity index 57% rename from tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt.sh rename to tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/_run_test.sh index 555ff502d1f..dcbfc6a753b 100755 --- a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt.sh +++ b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/_run_test.sh @@ -2,17 +2,18 @@ # Copyright 2022 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -simulation_id="gatt_change_aware" verbosity_level=2 -process_ids=""; exit_code=0 +process_ids="" +exit_code=0 -function Execute(){ - if [ ! -f $1 ]; then - echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\ +function Execute() { + if [ ! -f $1 ]; then + echo -e " \e[91m$(pwd)/$(basename $1) cannot be found (did you forget to\ compile it?)\e[39m" - exit 1 - fi - timeout 120 $@ & process_ids="$process_ids $!" + exit 1 + fi + timeout 120 $@ & + process_ids="$process_ids $!" } : "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}" @@ -23,15 +24,15 @@ BOARD="${BOARD:-nrf52_bsim}" cd ${BSIM_OUT_PATH}/bin Execute ./bs_${BOARD}_tests_bluetooth_bsim_bt_bsim_test_gatt_caching_prj_conf \ - -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=gatt_client + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=${client_id} Execute ./bs_${BOARD}_tests_bluetooth_bsim_bt_bsim_test_gatt_caching_prj_conf \ - -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=gatt_server + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=${server_id} Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ - -D=2 -sim_length=60e6 $@ + -D=2 -sim_length=60e6 $@ for process_id in $process_ids; do - wait $process_id || let "exit_code=$?" + wait $process_id || let "exit_code=$?" done exit $exit_code #the last exit code != 0 diff --git a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_db_hash_read_eatt.sh b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_db_hash_read_eatt.sh new file mode 100755 index 00000000000..fc9fc3675b5 --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_db_hash_read_eatt.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Copyright 2022 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +simulation_id="gatt_caching_db_hash_read_eatt" \ + client_id="gatt_client_db_hash_read_eatt" \ + server_id="gatt_server_eatt" \ + $(dirname "${BASH_SOURCE[0]}")/_run_test.sh diff --git a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_db_hash_read_no_eatt.sh b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_db_hash_read_no_eatt.sh new file mode 100755 index 00000000000..acafc89515a --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_db_hash_read_no_eatt.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Copyright 2022 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +simulation_id="gatt_caching_db_hash_read_no_eatt" \ + client_id="gatt_client_db_hash_read_no_eatt" \ + server_id="gatt_server_no_eatt" \ + $(dirname "${BASH_SOURCE[0]}")/_run_test.sh diff --git a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_out_of_sync_eatt.sh b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_out_of_sync_eatt.sh new file mode 100755 index 00000000000..7326530b023 --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_out_of_sync_eatt.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Copyright 2022 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +simulation_id="gatt_caching_out_of_sync_eatt" \ + client_id="gatt_client_out_of_sync_eatt" \ + server_id="gatt_server_eatt" \ + $(dirname "${BASH_SOURCE[0]}")/_run_test.sh diff --git a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_out_of_sync_no_eatt.sh b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_out_of_sync_no_eatt.sh new file mode 100755 index 00000000000..bfab7cf6c85 --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_out_of_sync_no_eatt.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Copyright 2022 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +simulation_id="gatt_caching_out_of_sync_no_eatt" \ + client_id="gatt_client_out_of_sync_no_eatt" \ + server_id="gatt_server_no_eatt" \ + $(dirname "${BASH_SOURCE[0]}")/_run_test.sh diff --git a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_retry_reads_eatt.sh b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_retry_reads_eatt.sh new file mode 100755 index 00000000000..b9b9c960c45 --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_retry_reads_eatt.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Copyright 2022 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +simulation_id="gatt_caching_retry_reads_eatt" \ + client_id="gatt_client_retry_reads_eatt" \ + server_id="gatt_server_eatt" \ + $(dirname "${BASH_SOURCE[0]}")/_run_test.sh diff --git a/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_retry_reads_no_eatt.sh b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_retry_reads_no_eatt.sh new file mode 100755 index 00000000000..2b7fda8fa94 --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_gatt_caching/test_scripts/gatt_caching_retry_reads_no_eatt.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Copyright 2022 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +simulation_id="gatt_caching_retry_reads_no_eatt" \ + client_id="gatt_client_retry_reads_no_eatt" \ + server_id="gatt_server_no_eatt" \ + $(dirname "${BASH_SOURCE[0]}")/_run_test.sh