diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/CMakeLists.txt b/tests/subsys/mgmt/mcumgr/os_mgmt_info/CMakeLists.txt new file mode 100644 index 00000000000..552c82052be --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(os_mgmt_info) + +FILE(GLOB app_sources + src/*.c +) + +target_sources(app PRIVATE ${app_sources}) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/mgmt/mcumgr/grp/os_mgmt/include/) + +if(DEFINED CONFIG_BUILD_DATE_TIME_TEST) + set(TEST_DATE_TIME_DIR ${PROJECT_BINARY_DIR}/test) + file(MAKE_DIRECTORY ${TEST_DATE_TIME_DIR}) + file(WRITE ${TEST_DATE_TIME_DIR}/test_date.c "/* Auto generated file, do not edit */\n#include \nuint8_t *test_date_time = __TIMESTAMP__;") + target_sources(app PRIVATE ${TEST_DATE_TIME_DIR}/test_date.c) +endif() diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/Kconfig b/tests/subsys/mgmt/mcumgr/os_mgmt_info/Kconfig new file mode 100644 index 00000000000..e63a1416584 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2022 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config CUSTOM_OS_NAME_VALUE + string "Custom OS name" + default "Fake OS Name" + +config BUILD_DATE_TIME_TEST + bool "Build date time test" + select MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME + +config LIMITED_TEST + bool "Limited buffer size test" + +source "Kconfig.zephyr" diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv32_smp.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv32_smp.conf new file mode 100644 index 00000000000..1ede042960b --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv32_smp.conf @@ -0,0 +1 @@ +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64.conf new file mode 100644 index 00000000000..1ede042960b --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64.conf @@ -0,0 +1 @@ +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64_smp.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64_smp.conf new file mode 100644 index 00000000000..1ede042960b --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64_smp.conf @@ -0,0 +1 @@ +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/prj.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_info/prj.conf new file mode 100644 index 00000000000..2166e715625 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/prj.conf @@ -0,0 +1,15 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_ZTEST=y +CONFIG_MCUMGR=y +CONFIG_MCUMGR_SMP_DUMMY=y +CONFIG_MCUMGR_SMP_DUMMY_RX_BUF_SIZE=256 +CONFIG_MCUMGR_CMD_OS_MGMT=y +CONFIG_MCUMGR_GRP_OS_INFO=y +CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS=y +CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS=y +CONFIG_ZTEST_NEW_API=y +CONFIG_ZTEST_STACK_SIZE=2048 diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/build_date.c b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/build_date.c new file mode 100644 index 00000000000..98b92677a09 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/build_date.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_BUILD_DATE_TIME_TEST) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smp_test_util.h" + +#define SMP_RESPONSE_WAIT_TIME 3 +#define ZCBOR_BUFFER_SIZE 256 +#define OUTPUT_BUFFER_SIZE 256 +#define ZCBOR_HISTORY_ARRAY_SIZE 4 + +static struct net_buf *nb; + +/* Responses to commands */ +extern uint8_t *test_date_time; +const uint8_t response_all_board_revision_left[] = "Zephyr unknown " STRINGIFY(BUILD_VERSION) " " + KERNEL_VERSION_STRING " "; +const uint8_t response_all_board_revision_right[] = " " CONFIG_ARCH " " PROCESSOR_NAME " " + CONFIG_BOARD "@" CONFIG_BOARD_REVISION + " Zephyr"; +const uint8_t response_all_left[] = "Zephyr unknown " STRINGIFY(BUILD_VERSION) " " + KERNEL_VERSION_STRING " "; +const uint8_t response_all_right[] = " " CONFIG_ARCH " " PROCESSOR_NAME " " CONFIG_BOARD " Zephyr"; + +const uint8_t query_build_date[] = "b"; +const uint8_t query_all[] = "a"; + +#define DATE_CHECK_LEFT_CHARS 11 +#define DATE_CHECK_RIGHT_CHARS 5 +#define TIME_CHECK_HH_START_CHAR 11 + +#define TIME_HH_OFFSET 0 +#define TIME_MM_OFFSET 3 +#define TIME_SS_OFFSET 6 + +#define SECONDS_PER_HOUR 3600 +#define SECONDS_PER_MINUTE 60 + +#define TIME_DIFFERENCE_ALLOWANCE 60 + +static int32_t time_string_to_seconds(const uint8_t *time_string) +{ + uint8_t time_hh; + uint8_t time_mm; + uint8_t time_ss; + + /* Convert times to separate fields and then to timestamps which can be compared */ + time_hh = ((time_string[TIME_HH_OFFSET] - '0') * 10) + + (time_string[TIME_HH_OFFSET + 1] - '0'); + time_mm = ((time_string[TIME_MM_OFFSET] - '0') * 10) + + (time_string[TIME_MM_OFFSET + 1] - '0'); + time_ss = ((time_string[TIME_SS_OFFSET] - '0') * 10) + + (time_string[TIME_SS_OFFSET + 1] - '0'); + + return (time_hh * SECONDS_PER_HOUR) + (time_mm * SECONDS_PER_MINUTE) + time_ss; +} + +ZTEST(os_mgmt_info_build_date, test_info_build_date_1_build_date) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t expected_time_seconds; + int32_t received_time_seconds; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_build_date, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send test echo command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal(strlen(test_date_time), output.len, + "Expected to receive %d bytes but got %d\n", + strlen(test_date_time), output.len); + + /* Check left and right sides of date which should match */ + zassert_mem_equal(test_date_time, output.value, DATE_CHECK_LEFT_CHARS, + "Expected received data mismatch"); + zassert_mem_equal(&test_date_time[(strlen(test_date_time) - DATE_CHECK_RIGHT_CHARS)], + &output.value[(strlen(test_date_time) - DATE_CHECK_RIGHT_CHARS)], + DATE_CHECK_RIGHT_CHARS, "Expected received data mismatch"); + + /* Extract time strings into timestamps */ + expected_time_seconds = time_string_to_seconds(&test_date_time[TIME_CHECK_HH_START_CHAR]); + received_time_seconds = time_string_to_seconds(&output.value[TIME_CHECK_HH_START_CHAR]); + + zassert_within(expected_time_seconds, received_time_seconds, TIME_DIFFERENCE_ALLOWANCE, + "Expected times to be within %d seconds but got %d", + TIME_DIFFERENCE_ALLOWANCE, + abs(expected_time_seconds - received_time_seconds)); +} + +ZTEST(os_mgmt_info_build_date, test_info_build_date_2_all) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t expected_time_seconds; + int32_t received_time_seconds; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_all, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send test echo command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + if (sizeof(CONFIG_BOARD_REVISION) > 1) { + /* Check with board revision */ + zassert_equal((strlen(test_date_time) + strlen(response_all_board_revision_left) + + strlen(response_all_board_revision_right)), output.len, + "Expected to receive %d bytes but got %d\n", + (strlen(test_date_time) + strlen(response_all_board_revision_left) + + strlen(response_all_board_revision_right)), output.len); + + zassert_mem_equal(response_all_board_revision_left, output.value, + strlen(response_all_board_revision_left), + "Expected received data mismatch"); + zassert_mem_equal(response_all_board_revision_right, + &output.value[strlen(response_all_board_revision_left) + + strlen(test_date_time)], + strlen(response_all_board_revision_right), + "Expected received data mismatch"); + } else { + /* Check without board revision */ + zassert_equal((strlen(test_date_time) + strlen(response_all_left) + + strlen(response_all_right)), output.len, + "Expected to receive %d bytes but got %d\n", + (strlen(test_date_time) + strlen(response_all_left) + + strlen(response_all_right)), output.len); + + zassert_mem_equal(response_all_left, output.value, strlen(response_all_left), + "Expected received data mismatch"); + zassert_mem_equal(response_all_right, &output.value[strlen(response_all_left) + + strlen(test_date_time)], strlen(response_all_right), + "Expected received data mismatch"); + } + + /* Extract time strings into timestamps */ + expected_time_seconds = time_string_to_seconds(&test_date_time[TIME_CHECK_HH_START_CHAR]); + received_time_seconds = time_string_to_seconds(&output.value[(strlen(response_all_left) + + TIME_CHECK_HH_START_CHAR)]); + + zassert_within(expected_time_seconds, received_time_seconds, TIME_DIFFERENCE_ALLOWANCE, + "Expected times to be within %d seconds but got %d", + TIME_DIFFERENCE_ALLOWANCE, + abs(expected_time_seconds - received_time_seconds)); +} + +static void *setup_tests(void) +{ + /* Register os_mgmt mcumgr group */ + os_mgmt_register_group(); + + return NULL; +} + +static void cleanup_test(void *p) +{ + if (nb != NULL) { + net_buf_unref(nb); + nb = NULL; + } +} + +/* Build date/time test set */ +ZTEST_SUITE(os_mgmt_info_build_date, NULL, setup_tests, NULL, cleanup_test, NULL); + +#endif diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/limited.c b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/limited.c new file mode 100644 index 00000000000..e06faee6c08 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/limited.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_LIMITED_TEST) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smp_test_util.h" + +#define SMP_RESPONSE_WAIT_TIME 3 +#define ZCBOR_BUFFER_SIZE 64 +#define OUTPUT_BUFFER_SIZE 64 +#define ZCBOR_HISTORY_ARRAY_SIZE 4 + +static struct net_buf *nb; + +/* Responses to commands */ +const uint8_t response_kernel_name[] = "Zephyr"; + +const uint8_t query_kernel_name[] = "s"; +const uint8_t query_all[] = "a"; + +ZTEST(os_mgmt_info_limited, test_info_1_kernel_name) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_kernel_name, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_kernel_name) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_kernel_name) - 1), output.len); + + zassert_mem_equal(response_kernel_name, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info_limited, test_info_2_all) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + struct zcbor_map_decode_key_val error_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(rc, zcbor_int32_decode, &rc), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_all, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + /* Ensure only an error is received */ + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); + + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + zassert_equal(output.len, 0, "Expected to receive 0 bytes but got %d\n", output.len); + zassert_equal(rc, MGMT_ERR_EMSGSIZE, "Expected to receive EMSGSIZE error but got %d\n", + rc); +} + +static void *setup_tests(void) +{ + /* Register os_mgmt mcumgr group */ + os_mgmt_register_group(); + + return NULL; +} + +static void cleanup_test(void *p) +{ + if (nb != NULL) { + net_buf_unref(nb); + nb = NULL; + } +} + +/* Limited size buffer test set */ +ZTEST_SUITE(os_mgmt_info_limited, NULL, setup_tests, NULL, cleanup_test, NULL); + +#endif diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c new file mode 100644 index 00000000000..0a9734467a2 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c @@ -0,0 +1,1562 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if !defined(CONFIG_BUILD_DATE_TIME_TEST) && !defined(CONFIG_LIMITED_TEST) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smp_test_util.h" + +#define SMP_RESPONSE_WAIT_TIME 3 +#define QUERY_BUFFER_SIZE 16 +#define ZCBOR_BUFFER_SIZE 256 +#define OUTPUT_BUFFER_SIZE 256 +#define ZCBOR_HISTORY_ARRAY_SIZE 4 +#define QUERY_TEST_CMD_BITMASK OS_MGMT_INFO_FORMAT_USER_CUSTOM_START + +/* Test sets */ +enum { + OS_MGMT_TEST_SET_MAIN = 0, +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS + OS_MGMT_TEST_SET_CUSTOM_OS, + OS_MGMT_TEST_SET_CUSTOM_OS_DISABLED, + OS_MGMT_TEST_SET_CUSTOM_CMD_DISABLED, + OS_MGMT_TEST_SET_CUSTOM_CMD, + OS_MGMT_TEST_SET_CUSTOM_CMD_DISABLED_VERIFY, +#endif + + OS_MGMT_TEST_SET_COUNT +}; + +/* Test os_mgmt info command requesting 's' (kernel name) */ +static const uint8_t command[] = { + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x01, 0x07, + 0xbf, 0x66, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, + 0x61, 0x73, 0xff +}; + +/* Expected response from mcumgr */ +static const uint8_t expected_response[] = { + 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x07, + 0xbf, 0x66, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x66, 0x5a, 0x65, 0x70, 0x68, 0x79, 0x72, 0xff +}; + +static struct net_buf *nb; + +struct state { + uint8_t test_set; +}; + +static struct state test_state = { + .test_set = 0, +}; + +/* Responses to commands */ +const uint8_t response_kernel_name[] = "Zephyr"; + +#if defined(CONFIG_BT) +const uint8_t response_node_name[] = CONFIG_BT_DEVICE_NAME; +#elif defined(CONFIG_NET_HOSTNAME_ENABLE) +const uint8_t response_node_name[] = CONFIG_NET_HOSTNAME; +#else +const uint8_t response_node_name[] = "unknown"; +#endif + +const uint8_t response_kernel_release[] = STRINGIFY(BUILD_VERSION); +const uint8_t response_kernel_version[] = KERNEL_VERSION_STRING; +const uint8_t response_machine[] = CONFIG_ARCH; +const uint8_t response_processor[] = PROCESSOR_NAME; +const uint8_t response_board_revision[] = CONFIG_BOARD "@" CONFIG_BOARD_REVISION; +const uint8_t response_board[] = CONFIG_BOARD; +const uint8_t response_os[] = "Zephyr"; +const uint8_t response_custom_cmd[] = "Magic Output for Test"; +const uint8_t response_os_custom[] = CONFIG_CUSTOM_OS_NAME_VALUE; + +const uint8_t response_all_board_revision[] = "Zephyr " +#if defined(CONFIG_BT) + CONFIG_BT_DEVICE_NAME +#elif defined(CONFIG_NET_HOSTNAME_ENABLE) + CONFIG_NET_HOSTNAME +#else + "unknown" +#endif + " " STRINGIFY(BUILD_VERSION) " " + KERNEL_VERSION_STRING " " CONFIG_ARCH " " + PROCESSOR_NAME " " CONFIG_BOARD "@" + CONFIG_BOARD_REVISION " Zephyr"; + +const uint8_t response_all[] = "Zephyr " +#if defined(CONFIG_BT) + CONFIG_BT_DEVICE_NAME +#elif defined(CONFIG_NET_HOSTNAME_ENABLE) + CONFIG_NET_HOSTNAME +#else + "unknown" +#endif + " " STRINGIFY(BUILD_VERSION) " " KERNEL_VERSION_STRING " " + CONFIG_ARCH " " PROCESSOR_NAME " " CONFIG_BOARD " Zephyr"; + +const uint8_t query_kernel_name[] = "s"; +const uint8_t query_node_name[] = "n"; +const uint8_t query_kernel_release[] = "r"; +const uint8_t query_kernel_version[] = "v"; +const uint8_t query_machine[] = "m"; +const uint8_t query_processor[] = "p"; +const uint8_t query_platform[] = "i"; +const uint8_t query_os[] = "o"; +const uint8_t query_all[] = "a"; +const uint8_t query_test_cmd[] = "k"; + +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS +static int32_t os_mgmt_info_custom_os_callback(uint32_t event, int32_t rc, bool *abort_more, + void *data, size_t data_size) +{ + if (event == MGMT_EVT_OP_OS_MGMT_INFO_CHECK) { + struct os_mgmt_info_check *check_data = (struct os_mgmt_info_check *)data; + + *check_data->custom_os_name = true; + } else if (event == MGMT_EVT_OP_OS_MGMT_INFO_APPEND) { + int rc; + struct os_mgmt_info_append *append_data = (struct os_mgmt_info_append *)data; + + if (*append_data->format_bitmask & OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM) { + rc = snprintf(&append_data->output[*append_data->output_length], + (append_data->buffer_size - *append_data->output_length), + "%s%s", (*append_data->prior_output == true ? " " : ""), + CONFIG_CUSTOM_OS_NAME_VALUE); + + if (rc < 0 || + rc >= (append_data->buffer_size - *append_data->output_length)) { + *abort_more = true; + return -1; + } + + *append_data->output_length += (uint16_t)rc; + *append_data->prior_output = true; + *append_data->format_bitmask &= ~OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM; + } + } + + return MGMT_ERR_EOK; +} + +static struct mgmt_callback custom_os_check_callback = { + .callback = os_mgmt_info_custom_os_callback, + .event_id = MGMT_EVT_OP_OS_MGMT_INFO_CHECK, +}; + +static struct mgmt_callback custom_os_append_callback = { + .callback = os_mgmt_info_custom_os_callback, + .event_id = MGMT_EVT_OP_OS_MGMT_INFO_APPEND, +}; + +static int32_t os_mgmt_info_custom_cmd_callback(uint32_t event, int32_t rc, bool *abort_more, + void *data, size_t data_size) +{ + if (event == MGMT_EVT_OP_OS_MGMT_INFO_CHECK) { + struct os_mgmt_info_check *check_data = (struct os_mgmt_info_check *)data; + size_t i = 0; + + while (i < check_data->format->len) { + if (check_data->format->value[i] == query_test_cmd[0]) { + *check_data->format_bitmask |= QUERY_TEST_CMD_BITMASK; + ++(*check_data->valid_formats); + } + + ++i; + } + } else if (event == MGMT_EVT_OP_OS_MGMT_INFO_APPEND) { + int rc; + struct os_mgmt_info_append *append_data = (struct os_mgmt_info_append *)data; + + if (append_data->all_format_specified || + (*append_data->format_bitmask & QUERY_TEST_CMD_BITMASK)) { + rc = snprintf(&append_data->output[*append_data->output_length], + (append_data->buffer_size - *append_data->output_length), + "%sMagic Output for Test", + (*append_data->prior_output == true ? " " : "")); + + if (rc < 0 || + rc >= (append_data->buffer_size - *append_data->output_length)) { + *abort_more = true; + return -1; + } + + *append_data->output_length += (uint16_t)rc; + *append_data->prior_output = true; + *append_data->format_bitmask &= ~QUERY_TEST_CMD_BITMASK; + } + } + + return MGMT_ERR_EOK; +} + +static struct mgmt_callback custom_cmd_check_callback = { + .callback = os_mgmt_info_custom_cmd_callback, + .event_id = MGMT_EVT_OP_OS_MGMT_INFO_CHECK, +}; + +static struct mgmt_callback custom_cmd_append_callback = { + .callback = os_mgmt_info_custom_cmd_callback, + .event_id = MGMT_EVT_OP_OS_MGMT_INFO_APPEND, +}; +#endif + +ZTEST(os_mgmt_info, test_info_1) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(command, sizeof(command)); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + bool received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + zassert_equal(sizeof(expected_response), nb->len, + "Expected to receive %d bytes but got %d\n", sizeof(expected_response), + nb->len); + + zassert_mem_equal(expected_response, nb->data, nb->len, + "Expected received data mismatch"); + + net_buf_unref(nb); + + /* Generate the same command dynamically */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, "s", buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Ensure the dynamically-generated size and payload matches the expected payload */ + zassert_equal(sizeof(command), buffer_size, + "Expected received data mismatch"); + zassert_mem_equal(command, buffer_out, sizeof(command), + "Expected received data mismatch"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + zassert_equal(sizeof(expected_response), nb->len, + "Expected to receive %d bytes but got %d\n", sizeof(expected_response), + nb->len); + + zassert_mem_equal(expected_response, nb->data, nb->len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_2_kernel_name) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_kernel_name, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_kernel_name) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_kernel_name) - 1), output.len); + + zassert_mem_equal(response_kernel_name, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_3_node_name) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_node_name, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_node_name) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_node_name) - 1), output.len); + + zassert_mem_equal(response_node_name, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_4_kernel_release) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_kernel_release, buffer, buffer_out, + &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_kernel_release) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_kernel_release) - 1), output.len); + + zassert_mem_equal(response_kernel_release, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_5_kernel_version) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_kernel_version, buffer, buffer_out, + &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_kernel_version) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_kernel_version) - 1), output.len); + + zassert_mem_equal(response_kernel_version, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_6_machine) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_machine, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_machine) - 1), output.len, + "Expected to receive %d bytes but got %d\n", (sizeof(response_machine) - 1), + output.len); + + zassert_mem_equal(response_machine, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_7_processor) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_processor, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_processor) - 1), output.len, + "Expected to receive %d bytes but got %d\n", (sizeof(response_processor) - 1), + output.len); + + zassert_mem_equal(response_processor, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_8_platform) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_platform, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + if (sizeof(CONFIG_BOARD_REVISION) > 1) { + /* Check with board revision */ + zassert_equal((sizeof(response_board_revision) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_board_revision) - 1), output.len); + + zassert_mem_equal(response_board_revision, output.value, output.len, + "Expected received data mismatch"); + } else { + /* Check without board revision */ + zassert_equal((sizeof(response_board) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_board) - 1), output.len); + + zassert_mem_equal(response_board, output.value, output.len, + "Expected received data mismatch"); + } +} + +ZTEST(os_mgmt_info, test_info_9_os) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_os, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_os) - 1), output.len, + "Expected to receive %d bytes but got %d\n", (sizeof(response_os) - 1), + output.len); + + zassert_mem_equal(response_os, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_10_all) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_all, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + if (sizeof(CONFIG_BOARD_REVISION) > 1) { + /* Check with board revision */ + zassert_equal((sizeof(response_all_board_revision) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_all_board_revision) - 1), output.len); + + zassert_mem_equal(response_all_board_revision, output.value, output.len, + "Expected received data mismatch"); + } else { + /* Check without board revision */ + zassert_equal((sizeof(response_all) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_all) - 1), output.len); + + zassert_mem_equal(response_all, output.value, output.len, + "Expected received data mismatch"); + } +} + +ZTEST(os_mgmt_info, test_info_11_multi_1) +{ + uint8_t query[QUERY_BUFFER_SIZE]; + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + /* Construct query for processor, kernel release and OS name */ + sprintf(query, "%s%s%s", query_processor, query_kernel_release, query_os); + ok = create_mcumgr_format_packet(zse, query, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + /* Construct expected response to be compared against */ + sprintf(buffer, "%s %s %s", response_kernel_release, response_processor, response_os); + + zassert_equal(strlen(buffer), output.len, "Expected to receive %d bytes but got %d\n", + strlen(buffer), output.len); + + zassert_mem_equal(buffer, output.value, output.len, "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_12_multi_2) +{ + uint8_t query[QUERY_BUFFER_SIZE]; + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + /* Construct query for node name and kernel version (twice) */ + sprintf(query, "%s%s%s", query_kernel_version, query_node_name, query_kernel_version); + ok = create_mcumgr_format_packet(zse, query, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + /* Construct expected response to be compared against, only 2 responses will be returned + * despite 3 being sent, because 2 were duplicates + */ + sprintf(buffer, "%s %s", response_node_name, response_kernel_version); + + zassert_equal(strlen(buffer), output.len, "Expected to receive %d bytes but got %d\n", + strlen(buffer), output.len); + + zassert_mem_equal(buffer, output.value, output.len, "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_13_invalid_1) +{ + uint8_t query[QUERY_BUFFER_SIZE]; + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + struct zcbor_map_decode_key_val error_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(rc, zcbor_int32_decode, &rc), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + /* Construct query for node name with invalid specifier */ + sprintf(query, "%sM", query_kernel_version); + ok = create_mcumgr_format_packet(zse, query, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + /* Ensure only an error is received */ + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); + + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + zassert_equal(output.len, 0, "Expected to receive 0 bytes but got %d\n", output.len); + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected to receive EINVAL error but got %d\n", rc); +} + +ZTEST(os_mgmt_info, test_info_14_invalid_2) +{ + uint8_t query[QUERY_BUFFER_SIZE]; + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + struct zcbor_map_decode_key_val error_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(rc, zcbor_int32_decode, &rc), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + /* Construct query for processor with invalid specifier */ + sprintf(query, "2%s", query_processor); + ok = create_mcumgr_format_packet(zse, query, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + /* Ensure only an error is received */ + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); + + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + zassert_equal(output.len, 0, "Expected to receive 0 bytes but got %d\n", output.len); + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected to receive EINVAL error but got %d\n", rc); +} + +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS +static void *setup_custom_os(void) +{ + mgmt_callback_register(&custom_os_check_callback); + mgmt_callback_register(&custom_os_append_callback); + return NULL; +} + +static void destroy_custom_os(void *p) +{ + mgmt_callback_unregister(&custom_os_check_callback); + mgmt_callback_unregister(&custom_os_append_callback); +} + +ZTEST(os_mgmt_info_custom_os, test_info_os_custom) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_os, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_os_custom) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_os_custom) - 1), output.len); + + zassert_mem_equal(response_os_custom, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info_custom_os_disabled, test_info_os_custom_disabled) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_os, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_os) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_os) - 1), output.len); + + zassert_mem_equal(response_os, output.value, output.len, + "Expected received data mismatch"); +} + +static void *setup_custom_cmd(void) +{ + mgmt_callback_register(&custom_cmd_check_callback); + mgmt_callback_register(&custom_cmd_append_callback); + + return NULL; +} + +static void destroy_custom_cmd(void *p) +{ + mgmt_callback_unregister(&custom_cmd_check_callback); + mgmt_callback_unregister(&custom_cmd_append_callback); +} + +ZTEST(os_mgmt_info_custom_cmd, test_info_cmd_custom) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_test_cmd, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_custom_cmd) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_custom_cmd) - 1), output.len); + + zassert_mem_equal(response_custom_cmd, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info_custom_cmd_disabled, test_info_cmd_custom_disabled) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + struct zcbor_map_decode_key_val error_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(rc, zcbor_int32_decode, &rc), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_test_cmd, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); + + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal(output.len, 0, "Expected to receive 0 bytes but got %d\n", output.len); + + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected to receive EINVAL error but got %d\n", rc); +} + +ZTEST(os_mgmt_info_custom_cmd_disabled_verify, test_info_cmd_custom_disabled) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + struct zcbor_map_decode_key_val error_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(rc, zcbor_int32_decode, &rc), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_test_cmd, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); + + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal(output.len, 0, "Expected to receive 0 bytes but got %d\n", output.len); + + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected to receive EINVAL error but got %d\n", rc); + +} +#endif + +static void cleanup_test(void *p) +{ + if (nb != NULL) { + net_buf_unref(nb); + nb = NULL; + } +} + +void test_main(void) +{ + /* Register os_mgmt mcumgr group */ + os_mgmt_register_group(); + + while (test_state.test_set < OS_MGMT_TEST_SET_COUNT) { + ztest_run_all(&test_state); + ++test_state.test_set; + } + + ztest_verify_all_test_suites_ran(); +} + +static bool main_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_TEST_SET_MAIN; +} + +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS +static bool custom_os_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_TEST_SET_CUSTOM_OS; +} + +static bool custom_os_disabled_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_TEST_SET_CUSTOM_OS_DISABLED; +} + +static bool custom_cmd_disabled_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_TEST_SET_CUSTOM_CMD_DISABLED; +} + +static bool custom_cmd_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_TEST_SET_CUSTOM_CMD; +} + +static bool custom_cmd_disabled_verify_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_TEST_SET_CUSTOM_CMD_DISABLED_VERIFY; +} +#endif + +/* Main test set */ +ZTEST_SUITE(os_mgmt_info, main_predicate, NULL, NULL, cleanup_test, NULL); + +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS +/* Custom OS test set */ +ZTEST_SUITE(os_mgmt_info_custom_os, custom_os_predicate, setup_custom_os, NULL, cleanup_test, + destroy_custom_os); +ZTEST_SUITE(os_mgmt_info_custom_os_disabled, custom_os_disabled_predicate, NULL, NULL, + cleanup_test, NULL); + +/* Custom cmd test set */ +ZTEST_SUITE(os_mgmt_info_custom_cmd_disabled, custom_cmd_disabled_predicate, NULL, NULL, + cleanup_test, NULL); +ZTEST_SUITE(os_mgmt_info_custom_cmd, custom_cmd_predicate, setup_custom_cmd, NULL, cleanup_test, + destroy_custom_cmd); +ZTEST_SUITE(os_mgmt_info_custom_cmd_disabled_verify, custom_cmd_disabled_verify_predicate, NULL, + NULL, cleanup_test, NULL); +#endif + +#endif diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.c b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.c new file mode 100644 index 00000000000..c1dcded0ff6 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "smp_test_util.h" +#include +#include +#include +#include + +/* SMP header function for generating os_mgmt info command header with sequence number set to 1 */ +void smp_make_hdr(struct smp_hdr *rsp_hdr, size_t len) +{ + *rsp_hdr = (struct smp_hdr) { + .nh_len = sys_cpu_to_be16(len), + .nh_flags = 0, + .nh_op = 0, + .nh_group = sys_cpu_to_be16(MGMT_GROUP_ID_OS), + .nh_seq = 1, + .nh_id = OS_MGMT_ID_INFO, + }; +} + +/* Function for creating an os_mgmt info command */ +bool create_mcumgr_format_packet(zcbor_state_t *zse, const uint8_t *format, uint8_t *buffer, + uint8_t *output_buffer, uint16_t *buffer_size) +{ + bool ok; + + ok = zcbor_map_start_encode(zse, 2) && + zcbor_tstr_put_lit(zse, "format") && + zcbor_tstr_put_term(zse, format) && + zcbor_map_end_encode(zse, 2); + + *buffer_size = (zse->payload_mut - buffer); + smp_make_hdr((struct smp_hdr *)output_buffer, *buffer_size); + memcpy(&output_buffer[sizeof(struct smp_hdr)], buffer, *buffer_size); + *buffer_size += sizeof(struct smp_hdr); + + return ok; +} diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.h b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.h new file mode 100644 index 00000000000..1b28b850781 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_SMP_TEST_UTIL_ +#define H_SMP_TEST_UTIL_ + +#include +#include +#include +#include + +/* SMP header function for generating os_mgmt info command header with sequence number set to 1 */ +void smp_make_hdr(struct smp_hdr *rsp_hdr, size_t len); + +/* Function for creating an os_mgmt info command */ +bool create_mcumgr_format_packet(zcbor_state_t *zse, const uint8_t *format, uint8_t *buffer, + uint8_t *output_buffer, uint16_t *buffer_size); + + +#endif diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml b/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml new file mode 100644 index 00000000000..4ff0292b6da --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml @@ -0,0 +1,57 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +tests: + os.mgmt.info: + # FIXME: Exclude architectures that lack a reboot handler function + # FIXME: Exclude systems whereby the processor type is not known and emits a warning + arch_exclude: arm64 nios2 sparc arc xtensa mips posix + tags: os_mgmt_info + os.mgmt.info_no_hooks: + # FIXME: Exclude architectures that lack a reboot handler function + # FIXME: Exclude systems whereby the processor type is not known and emits a warning + arch_exclude: arm64 nios2 sparc arc xtensa mips posix + tags: os_mgmt_info + extra_configs: + - CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS=n + - CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS=n + os.mgmt.info_bt: + depends_on: ble + # FIXME: Exclude architectures that lack a reboot handler function + # FIXME: Exclude systems whereby the processor type is not known and emits a warning + arch_exclude: arm64 nios2 sparc arc xtensa mips posix + tags: os_mgmt_info + extra_configs: + - CONFIG_BT=y + - CONFIG_BT_DEVICE_NAME="a_bt_name" + os.mgmt.info_net: + depends_on: netif + # FIXME: Exclude architectures that lack a reboot handler function + # FIXME: Exclude systems whereby the processor type is not known and emits a warning + arch_exclude: arm64 nios2 sparc arc xtensa mips posix + platform_exclude: qemu_cortex_a9 qemu_x86 qemu_riscv64_smp qemu_riscv64 qemu_riscv32e + qemu_riscv32 qemu_riscv32_smp qemu_cortex_m3 mps2_an385 + tags: os_mgmt_info + extra_configs: + - CONFIG_NETWORKING=y + - CONFIG_NET_HOSTNAME_ENABLE=y + - CONFIG_NET_HOSTNAME="test_net_name" + - CONFIG_TEST_RANDOM_GENERATOR=y + os.mgmt.info_build_date: + # FIXME: Exclude architectures that lack a reboot handler function + # FIXME: Exclude systems whereby the processor type is not known and emits a warning + arch_exclude: arm64 nios2 sparc arc xtensa mips posix + tags: os_mgmt_info + extra_configs: + - CONFIG_BUILD_DATE_TIME_TEST=y + os.mgmt.info_limited_size: + # FIXME: Exclude architectures that lack a reboot handler function + # FIXME: Exclude systems whereby the processor type is not known and emits a warning + arch_exclude: arm64 nios2 sparc arc xtensa mips posix + tags: os_mgmt_info + extra_configs: + - CONFIG_LIMITED_TEST=y + - CONFIG_MCUMGR_SMP_DUMMY_RX_BUF_SIZE=64 + - CONFIG_MCUMGR_GRP_OS_INFO_MAX_RESPONSE_SIZE=32