diff --git a/CODEOWNERS b/CODEOWNERS index 8f4482182e..7740c65e49 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -90,6 +90,7 @@ /tests/lib/ble_qwr/ @nrfconnect/ncs-bm /tests/lib/ble_racp/ @nrfconnect/ncs-bm /tests/lib/ble_adv/ @nrfconnect/ncs-bm-test +/tests/lib/ble_gq/ @nrfconnect/ncs-bm @nrfconnect/ncs-bm-test /tests/lib/bm_storage/ @nrfconnect/ncs-bm /tests/lib/bm_timer/ @nrfconnect/ncs-bm @nrfconnect/ncs-bm-test diff --git a/tests/lib/ble_gq/CMakeLists.txt b/tests/lib/ble_gq/CMakeLists.txt new file mode 100644 index 0000000000..1e334c4cfc --- /dev/null +++ b/tests/lib/ble_gq/CMakeLists.txt @@ -0,0 +1,38 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(unit_test_ble_gq) + +set(SOFTDEVICE_VARIANT "s115") +set(SOFTDEVICE_INCLUDE_DIR "${ZEPHYR_NRF_BM_MODULE_DIR}/components/softdevice/\ +${SOFTDEVICE_VARIANT}/${SOFTDEVICE_VARIANT}_API/include") + +cmock_handle(${SOFTDEVICE_INCLUDE_DIR}/ble_gattc.h) +cmock_handle(${SOFTDEVICE_INCLUDE_DIR}/ble_gatts.h) + +target_compile_definitions(app PRIVATE + NRF54L15_XXAA + SVCALL_AS_NORMAL_FUNCTION + SUPPRESS_INLINE_IMPLEMENTATION + CONFIG_NRF_SDH_BLE_TOTAL_LINK_COUNT=2 + CONFIG_BLE_GQ_HEAP_SIZE=1024 +) + +target_include_directories(app PRIVATE + ${SOFTDEVICE_INCLUDE_DIR} + ${ZEPHYR_HAL_NORDIC_MODULE_DIR}/nrfx/mdk +) + +# Generate and add test file +test_runner_generate(src/unity_test.c) +target_sources(app PRIVATE src/unity_test.c) + +# Unit under test +target_sources(app PRIVATE ${ZEPHYR_NRF_BM_MODULE_DIR}/lib/ble_gq/gatt_queue.c) diff --git a/tests/lib/ble_gq/prj.conf b/tests/lib/ble_gq/prj.conf new file mode 100644 index 0000000000..a8788847da --- /dev/null +++ b/tests/lib/ble_gq/prj.conf @@ -0,0 +1,6 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# +CONFIG_UNITY=y diff --git a/tests/lib/ble_gq/src/unity_test.c b/tests/lib/ble_gq/src/unity_test.c new file mode 100644 index 0000000000..635e289601 --- /dev/null +++ b/tests/lib/ble_gq/src/unity_test.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include + +#include +#include +#include +#include + +#include "cmock_ble_gattc.h" +#include "cmock_ble_gatts.h" + +#define MAX_CONNS 2 +#define BLE_GQ_REQ_UNDEFINED 7 +#define BLE_GQ_QUEUE_SIZE 8 +#define BLE_GQ_HEAP_SIZE 1024 + +BLE_GQ_CUSTOM_DEF(ble_gq, MAX_CONNS, BLE_GQ_HEAP_SIZE, MAX_CONNS * BLE_GQ_QUEUE_SIZE); +static uint16_t glob_conn_handle; +static uint32_t glob_error; + +static void ble_gq_error_handler(uint16_t conn_handle, uint32_t err, void *ctx) +{ + glob_conn_handle = conn_handle; + glob_error = err; +} + +void test_ble_gq_item_add_efault(void) +{ + struct ble_gq_req req = {0}; + int ret; + + ret = ble_gq_item_add(NULL, &req, 1); + TEST_ASSERT_EQUAL(-EFAULT, ret); + + ret = ble_gq_item_add(&ble_gq, NULL, 1); + TEST_ASSERT_EQUAL(-EFAULT, ret); +} + +void test_ble_gq_item_add_einval(void) +{ + struct ble_gq_req req = {.type = BLE_GQ_REQ_NUM}; + int ret; + + ret = ble_gq_item_add(&ble_gq, &req, 0); + TEST_ASSERT_EQUAL(-EINVAL, ret); + + ret = ble_gq_item_add(&ble_gq, &req, 99); + TEST_ASSERT_EQUAL(-EINVAL, ret); +} + +void test_ble_gq_item_add_req_gatt_read(void) +{ + uint16_t conn_handle = 0; + int ret; + struct ble_gq_req req = { + .type = BLE_GQ_REQ_GATTC_READ, + .error_handler = { + .cb = ble_gq_error_handler, + .ctx = NULL + }, + .gattc_read = { + .handle = 0, + .offset = 0 + } + }; + ble_gq.conn_handles[0] = 0; + + __cmock_sd_ble_gattc_read_ExpectAndReturn(conn_handle, req.gattc_read.handle, + req.gattc_read.offset, NRF_ERROR_BUSY); + __cmock_sd_ble_gattc_read_ExpectAndReturn(conn_handle, req.gattc_read.handle, + req.gattc_read.offset, NRF_ERROR_INVALID_STATE); + + ret = ble_gq_item_add(&ble_gq, &req, conn_handle); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(conn_handle, glob_conn_handle); + TEST_ASSERT_EQUAL(NRF_ERROR_INVALID_STATE, glob_error); +} + +void test_ble_gq_item_add_req_gatt_write(void) +{ + uint16_t conn_handle = 0; + int ret; + struct ble_gq_req req = { + .type = BLE_GQ_REQ_GATTC_WRITE, + .error_handler = { + .cb = ble_gq_error_handler, + .ctx = NULL + }, + .gattc_write = { + .handle = 0, + .offset = 0, + .len = sizeof("testdata"), + .p_value = "testdata" + } + }; + ble_gq.conn_handles[0] = 0; + + __cmock_sd_ble_gattc_write_ExpectAndReturn(conn_handle, &req.gattc_write, NRF_ERROR_BUSY); + __cmock_sd_ble_gattc_write_IgnoreAndReturn(NRF_ERROR_RESOURCES); + ret = ble_gq_item_add(&ble_gq, &req, conn_handle); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(conn_handle, glob_conn_handle); + TEST_ASSERT_EQUAL(NRF_ERROR_RESOURCES, glob_error); +} + +void test_ble_gq_item_add_req_srv_discovery(void) +{ + uint16_t conn_handle = 0; + int ret; + struct ble_gq_req req = { + .type = BLE_GQ_REQ_SRV_DISCOVERY, + .error_handler = { + .cb = ble_gq_error_handler, + .ctx = NULL + }, + .gattc_srv_disc = { + .start_handle = 0, + .srvc_uuid = {0} + } + }; + ble_gq.conn_handles[0] = 0; + + __cmock_sd_ble_gattc_primary_services_discover_ExpectAndReturn( + conn_handle, req.gattc_srv_disc.start_handle, &req.gattc_srv_disc.srvc_uuid, + NRF_ERROR_BUSY); + __cmock_sd_ble_gattc_primary_services_discover_ExpectAndReturn( + conn_handle, req.gattc_srv_disc.start_handle, &req.gattc_srv_disc.srvc_uuid, + NRF_ERROR_TIMEOUT); + + ret = ble_gq_item_add(&ble_gq, &req, 0); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(conn_handle, glob_conn_handle); + TEST_ASSERT_EQUAL(NRF_ERROR_TIMEOUT, glob_error); +} + +void test_ble_gq_item_add_req_char_discovery(void) +{ + uint16_t conn_handle = 0; + int ret; + struct ble_gq_req req = { + .type = BLE_GQ_REQ_CHAR_DISCOVERY, + .error_handler = { + .cb = ble_gq_error_handler, + .ctx = NULL + }, + .gattc_char_disc = { + .start_handle = 0, + .end_handle = 0 + } + }; + ble_gq.conn_handles[0] = 0; + + __cmock_sd_ble_gattc_characteristics_discover_ExpectAndReturn( + conn_handle, &req.gattc_char_disc, NRF_ERROR_BUSY); + __cmock_sd_ble_gattc_characteristics_discover_ExpectAndReturn( + conn_handle, &req.gattc_char_disc, NRF_ERROR_INVALID_ADDR); + + ret = ble_gq_item_add(&ble_gq, &req, 0); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(conn_handle, glob_conn_handle); + TEST_ASSERT_EQUAL(NRF_ERROR_INVALID_ADDR, glob_error); +} + +void test_ble_gq_item_add_req_desc_discovery(void) +{ + uint16_t conn_handle = 0; + int ret; + struct ble_gq_req req = { + .type = BLE_GQ_REQ_DESC_DISCOVERY, + .error_handler = { + .cb = ble_gq_error_handler, + .ctx = NULL + }, + .gattc_desc_disc = { + .start_handle = 0, + .end_handle = 0 + } + }; + ble_gq.conn_handles[0] = 0; + + __cmock_sd_ble_gattc_descriptors_discover_ExpectAndReturn( + conn_handle, &req.gattc_desc_disc, NRF_ERROR_BUSY); + __cmock_sd_ble_gattc_descriptors_discover_ExpectAndReturn( + conn_handle, &req.gattc_desc_disc, BLE_ERROR_INVALID_CONN_HANDLE); + + ret = ble_gq_item_add(&ble_gq, &req, 0); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(conn_handle, glob_conn_handle); + TEST_ASSERT_EQUAL(BLE_ERROR_INVALID_CONN_HANDLE, glob_error); +} + +void test_ble_gq_item_add_req_gatts_hvx(void) +{ + uint8_t data[] = { 0x01, 0x02, 0x03 }; + uint16_t len = sizeof(data); + uint16_t conn_handle = 0; + int ret; + struct ble_gq_req req = { + .type = BLE_GQ_REQ_GATTS_HVX, + .error_handler = { + .cb = ble_gq_error_handler, + .ctx = NULL + }, + .gatts_hvx = { + .type = BLE_GATT_HVX_NOTIFICATION, + .handle = 0, + .offset = 0, + .p_data = data, + .p_len = &len + } + }; + ble_gq.conn_handles[0] = 0; + + __cmock_sd_ble_gatts_hvx_ExpectAndReturn(conn_handle, &req.gatts_hvx, NRF_ERROR_BUSY); + __cmock_sd_ble_gatts_hvx_IgnoreAndReturn(NRF_SUCCESS); + ret = ble_gq_item_add(&ble_gq, &req, 0); + TEST_ASSERT_EQUAL(0, ret); + + __cmock_sd_ble_gatts_hvx_ExpectAndReturn(conn_handle, &req.gatts_hvx, NRF_ERROR_BUSY); + __cmock_sd_ble_gatts_hvx_IgnoreAndReturn(NRF_ERROR_INVALID_ADDR); + + ret = ble_gq_item_add(&ble_gq, &req, 0); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(conn_handle, glob_conn_handle); + TEST_ASSERT_EQUAL(NRF_ERROR_INVALID_ADDR, glob_error); + + req.gatts_hvx.p_len = NULL; + ret = ble_gq_item_add(&ble_gq, &req, 0); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(NRF_ERROR_INVALID_PARAM, glob_error); +} + +void test_ble_gq_conn_handle_register_efault(void) +{ + int ret = ble_gq_conn_handle_register(NULL, 0); + + TEST_ASSERT_EQUAL(-EFAULT, ret); +} + +void test_ble_gq_conn_handle_register_enomem(void) +{ + int ret; + + ret = ble_gq_conn_handle_register(&ble_gq, 0); + TEST_ASSERT_EQUAL(0, ret); + + for (int i = 0; i < ble_gq.max_conns; i++) { + ble_gq.conn_handles[i] = i + 1; + } + ret = ble_gq_conn_handle_register(&ble_gq, 3); + TEST_ASSERT_EQUAL(-ENOMEM, ret); +} + +void test_ble_gq_on_ble_evt(void) +{ + ble_evt_t ble_evt = {0}; + uint16_t conn_handle = 0x0C4; + + ble_evt.header.evt_id = BLE_GAP_EVT_DISCONNECTED; + ble_evt.evt.gap_evt.conn_handle = 0x0C4; + ble_gq.conn_handles[0] = 0x0C4; + + ble_gq_on_ble_evt(NULL, NULL); + + ble_gq_on_ble_evt(&ble_evt, (void *)&ble_gq); + TEST_ASSERT_EQUAL(ble_gq.conn_handles[0], BLE_CONN_HANDLE_INVALID); + + /* Verify that req_queue_purge_schedule cleared the connection id 0x0C4 + * on evt BLE_GAP_EVT_DISCONNECTED + */ + for (int i = 0; i < ble_gq.max_conns; i++) { + TEST_ASSERT_NOT_EQUAL(ble_gq.purge_list[i], 0x0C4); + } + + ble_evt.header.evt_id = BLE_GATTC_EVT_READ_RSP; + ble_evt.evt.gattc_evt.conn_handle = 0x0C4; + ble_gq.conn_handles[0] = 0x0C4; + static struct ble_gq_req req = { + .type = BLE_GQ_REQ_GATTC_READ, + .error_handler = { + .cb = ble_gq_error_handler, + .ctx = NULL + }, + .gattc_read = { + .handle = 0, + .offset = 0 + } + }; + + sys_slist_init(&ble_gq.req_queue[0]); + sys_slist_append(&ble_gq.req_queue[0], &req.node); + __cmock_sd_ble_gattc_read_ExpectAndReturn(conn_handle, req.gattc_read.handle, + req.gattc_read.offset, NRF_ERROR_TIMEOUT); + ble_gq_on_ble_evt(&ble_evt, (void *)&ble_gq); + TEST_ASSERT_EQUAL(conn_handle, glob_conn_handle); + TEST_ASSERT_EQUAL(NRF_ERROR_TIMEOUT, glob_error); +} + +extern int unity_main(void); + +int main(void) +{ + return unity_main(); +} diff --git a/tests/lib/ble_gq/testcase.yaml b/tests/lib/ble_gq/testcase.yaml new file mode 100644 index 0000000000..e6994b14fa --- /dev/null +++ b/tests/lib/ble_gq/testcase.yaml @@ -0,0 +1,4 @@ +tests: + lib.ble_gq: + platform_allow: native_sim + tags: unittest