From 1f928902831119b17b26f623f1fc6673835d4fa2 Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Fri, 13 Jun 2025 15:23:21 +0200 Subject: [PATCH] tests: upgrade: Upgrade with mcumgr using BLE transport Extend tests/boot/with_mcumgr with BLE configuration. Updated sample to use the source code from smp_svr. Signed-off-by: Grzegorz Chwierut --- tests/boot/with_mcumgr/CMakeLists.txt | 5 +- tests/boot/with_mcumgr/README.rst | 14 +++++- tests/boot/with_mcumgr/overlay-bt.conf | 47 ++++++++++++++++++ tests/boot/with_mcumgr/prj.conf | 48 +++++++++++++++---- tests/boot/with_mcumgr/pytest/conftest.py | 19 ++++++++ .../pytest/test_downgrade_prevention.py | 4 +- tests/boot/with_mcumgr/pytest/test_upgrade.py | 26 ++++++---- .../with_mcumgr/pytest/test_upgrade_ble.py | 16 +++++++ tests/boot/with_mcumgr/src/main.c | 14 ------ tests/boot/with_mcumgr/sysbuild/mcuboot.conf | 1 - tests/boot/with_mcumgr/testcase.yaml | 12 +++++ 11 files changed, 167 insertions(+), 39 deletions(-) create mode 100644 tests/boot/with_mcumgr/overlay-bt.conf create mode 100644 tests/boot/with_mcumgr/pytest/conftest.py create mode 100755 tests/boot/with_mcumgr/pytest/test_upgrade_ble.py delete mode 100644 tests/boot/with_mcumgr/src/main.c delete mode 100644 tests/boot/with_mcumgr/sysbuild/mcuboot.conf diff --git a/tests/boot/with_mcumgr/CMakeLists.txt b/tests/boot/with_mcumgr/CMakeLists.txt index 640c52434a4..be459aaa07a 100644 --- a/tests/boot/with_mcumgr/CMakeLists.txt +++ b/tests/boot/with_mcumgr/CMakeLists.txt @@ -5,5 +5,6 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(with_mcumgr) -FILE(GLOB app_sources src/*.c) -target_sources(app PRIVATE ${app_sources}) +# This project uses orginal C source code from smp_svr sample +target_sources(app PRIVATE ${ZEPHYR_BASE}/samples/subsys/mgmt/mcumgr/smp_svr/src/main.c) +target_sources_ifdef(CONFIG_MCUMGR_TRANSPORT_BT app PRIVATE ${ZEPHYR_BASE}/samples/subsys/mgmt/mcumgr/smp_svr/src/bluetooth.c) diff --git a/tests/boot/with_mcumgr/README.rst b/tests/boot/with_mcumgr/README.rst index e937d08163c..5c82efa137a 100644 --- a/tests/boot/with_mcumgr/README.rst +++ b/tests/boot/with_mcumgr/README.rst @@ -19,8 +19,18 @@ use following command: -p nrf52840dk/nrf52840 --device-testing --device-serial /dev/ttyACM0 .. note:: - Twister requires ``--west-flash`` flag enabled (without additional parameters - like ``erase``) to use sysbuild. + Twister requires ``--west-flash`` flag enabled to use sysbuild. + +To test with ``mcumgr`` with Bluetooth, one must add ``usb_hci:hciX`` fixture +where ``hciX`` is the Bluetooth HCI device (e.g. ``hci1``). +Fixture can be added to Twister command: ``-X usb_hci:hci1``, +or added to the hardware map + +.. code-block:: yaml + + - connected: true + fixtures: + - usb_hci:hci1 Test scripts can be found in ``pytest`` directory. To list available scenarios with described procedures, one can use a pytest command: diff --git a/tests/boot/with_mcumgr/overlay-bt.conf b/tests/boot/with_mcumgr/overlay-bt.conf new file mode 100644 index 00000000000..1b945465163 --- /dev/null +++ b/tests/boot/with_mcumgr/overlay-bt.conf @@ -0,0 +1,47 @@ +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y + +# Allow for large Bluetooth data packets. +CONFIG_BT_L2CAP_TX_MTU=498 +CONFIG_BT_BUF_ACL_RX_SIZE=502 +CONFIG_BT_BUF_ACL_TX_SIZE=502 +CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 + +# Enable the Bluetooth mcumgr transport (unauthenticated). +CONFIG_MCUMGR_TRANSPORT_BT=y +CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL=y + +# Enable the Shell mcumgr transport. +CONFIG_BASE64=y +CONFIG_CRC=y +CONFIG_SHELL=y +CONFIG_SHELL_BACKEND_SERIAL=y +CONFIG_MCUMGR_TRANSPORT_SHELL=y + +# Enable the mcumgr Packet Reassembly feature over Bluetooth and its configuration dependencies. +# MCUmgr buffer size is optimized to fit one SMP packet divided into five Bluetooth Write Commands, +# transmitted with the maximum possible MTU value: 498 bytes. +CONFIG_MCUMGR_TRANSPORT_BT_REASSEMBLY=y +CONFIG_MCUMGR_TRANSPORT_NETBUF_SIZE=2475 +CONFIG_MCUMGR_GRP_OS_MCUMGR_PARAMS=y +CONFIG_MCUMGR_TRANSPORT_WORKQUEUE_STACK_SIZE=4608 + +# Enable the LittleFS file system. +CONFIG_FILE_SYSTEM=y +CONFIG_FILE_SYSTEM_LITTLEFS=y + +# Enable file system commands +CONFIG_MCUMGR_GRP_FS=y + +# Enable the storage erase command. +CONFIG_MCUMGR_GRP_ZBASIC=y +CONFIG_MCUMGR_GRP_ZBASIC_STORAGE_ERASE=y + +# Disable Bluetooth ping support +CONFIG_BT_CTLR_LE_PING=n + +# Disable shell commands that are not needed +CONFIG_CLOCK_CONTROL_NRF_SHELL=n +CONFIG_DEVICE_SHELL=n +CONFIG_DEVMEM_SHELL=n +CONFIG_FLASH_SHELL=n diff --git a/tests/boot/with_mcumgr/prj.conf b/tests/boot/with_mcumgr/prj.conf index 3ddf7a4a45d..d55758d174d 100644 --- a/tests/boot/with_mcumgr/prj.conf +++ b/tests/boot/with_mcumgr/prj.conf @@ -6,18 +6,50 @@ CONFIG_MCUMGR=y CONFIG_STREAM_FLASH=y CONFIG_FLASH_MAP=y -# Enable the shell MCUmgr transport. -CONFIG_BASE64=y -CONFIG_SHELL=y -CONFIG_MCUBOOT_SHELL=y -CONFIG_SHELL_BACKEND_SERIAL=y -CONFIG_MCUMGR_TRANSPORT_SHELL=y +# Some command handlers require a large stack. +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304 +CONFIG_MAIN_STACK_SIZE=2048 + +# Ensure an MCUboot-compatible binary is generated. +CONFIG_BOOTLOADER_MCUBOOT=y + +# Enable flash operations. +CONFIG_FLASH=y + +# Required by the `taskstat` command. +CONFIG_THREAD_MONITOR=y + +# Support for taskstat command +CONFIG_MCUMGR_GRP_OS_TASKSTAT=y + +# Enable statistics and statistic names. +CONFIG_STATS=y +CONFIG_STATS_NAMES=y # Enable most core commands. CONFIG_FLASH=y CONFIG_IMG_MANAGER=y CONFIG_MCUMGR_GRP_IMG=y CONFIG_MCUMGR_GRP_OS=y +CONFIG_MCUMGR_GRP_STAT=y + +# Enable logging +CONFIG_LOG=y +CONFIG_MCUBOOT_UTIL_LOG_LEVEL_WRN=y + +# Disable debug logging +CONFIG_LOG_MAX_LEVEL=3 + +# Enable the Shell mcumgr transport. +CONFIG_BASE64=y +CONFIG_CRC=y +CONFIG_SHELL=y +CONFIG_SHELL_BACKEND_SERIAL=y +CONFIG_MCUMGR_TRANSPORT_SHELL=y +CONFIG_MCUBOOT_SHELL=y -# mcumgr-cli application doesn't accepts log in the channel it uses -CONFIG_SHELL_LOG_BACKEND=n +# Disable shell commands that are not needed +CONFIG_CLOCK_CONTROL_NRF_SHELL=n +CONFIG_DEVICE_SHELL=n +CONFIG_DEVMEM_SHELL=n +CONFIG_FLASH_SHELL=n diff --git a/tests/boot/with_mcumgr/pytest/conftest.py b/tests/boot/with_mcumgr/pytest/conftest.py new file mode 100644 index 00000000000..addeae8a056 --- /dev/null +++ b/tests/boot/with_mcumgr/pytest/conftest.py @@ -0,0 +1,19 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +import os +import sys + +# Add the directory to PYTHONPATH +zephyr_base = os.getenv("ZEPHYR_BASE") +if zephyr_base: + sys.path.insert( + 0, os.path.join(zephyr_base, "scripts", "pylib", "pytest-twister-harness", "src") + ) +else: + raise OSError("ZEPHYR_BASE environment variable is not set") + +pytest_plugins = [ + "twister_harness.plugin", +] diff --git a/tests/boot/with_mcumgr/pytest/test_downgrade_prevention.py b/tests/boot/with_mcumgr/pytest/test_downgrade_prevention.py index e974799c1d2..eb5ebc1c78d 100755 --- a/tests/boot/with_mcumgr/pytest/test_downgrade_prevention.py +++ b/tests/boot/with_mcumgr/pytest/test_downgrade_prevention.py @@ -6,7 +6,7 @@ from __future__ import annotations import logging from pathlib import Path -from test_upgrade import create_signed_image +from test_upgrade import WELCOME_STRING, create_signed_image from twister_harness import DeviceAdapter, MCUmgr, Shell from twister_harness.helpers.utils import find_in_config, match_lines, match_no_lines from utils import check_with_mcumgr_command, check_with_shell_command @@ -48,7 +48,7 @@ def test_downgrade_prevention(dut: DeviceAdapter, shell: Shell, mcumgr: MCUmgr): mcumgr.reset_device() dut.connect() - output = dut.readlines_until('Launching primary slot application') + output = dut.readlines_until(WELCOME_STRING) match_no_lines(output, ['Starting swap using move algorithm']) match_lines(output, ['erased due to downgrade prevention']) logger.info('Verify that the original APP is booted') diff --git a/tests/boot/with_mcumgr/pytest/test_upgrade.py b/tests/boot/with_mcumgr/pytest/test_upgrade.py index 733bd40f478..9d88da445ed 100755 --- a/tests/boot/with_mcumgr/pytest/test_upgrade.py +++ b/tests/boot/with_mcumgr/pytest/test_upgrade.py @@ -14,6 +14,9 @@ from west_sign_wrapper import west_sign_with_imgtool logger = logging.getLogger(__name__) +# This string is used to verify that the device is running the application +WELCOME_STRING = "smp_sample: build time:" + def create_signed_image(build_dir: Path, app_build_dir: Path, version: str) -> Path: image_to_test = Path(build_dir) / 'test_{}.signed.bin'.format( @@ -49,7 +52,7 @@ def clear_buffer(dut: DeviceAdapter) -> None: dut.disconnect() -def test_upgrade_with_confirm(dut: DeviceAdapter, shell: Shell, mcumgr: MCUmgr): +def run_upgrade_with_confirm(dut: DeviceAdapter, shell: Shell, mcumgr: MCUmgr): """ Verify that the application can be updated 1) Device flashed with MCUboot and an application that contains SMP server @@ -77,7 +80,7 @@ def test_upgrade_with_confirm(dut: DeviceAdapter, shell: Shell, mcumgr: MCUmgr): mcumgr.reset_device() dut.connect() - output = dut.readlines_until('Launching primary slot application') + output = dut.readlines_until(WELCOME_STRING) upgrade_string_to_verify = get_upgrade_string_to_verify(dut.device_config.build_dir) match_lines(output, [ 'Swap type: test', @@ -93,7 +96,7 @@ def test_upgrade_with_confirm(dut: DeviceAdapter, shell: Shell, mcumgr: MCUmgr): mcumgr.reset_device() dut.connect() - output = dut.readlines_until('Launching primary slot application') + output = dut.readlines_until(WELCOME_STRING) match_no_lines(output, [ upgrade_string_to_verify ]) @@ -101,6 +104,11 @@ def test_upgrade_with_confirm(dut: DeviceAdapter, shell: Shell, mcumgr: MCUmgr): check_with_shell_command(shell, new_version) +def test_upgrade_with_confirm(mcumgr: MCUmgr, dut: DeviceAdapter, shell: Shell): + """Verify that the application can be updated over serial""" + run_upgrade_with_confirm(dut, shell, mcumgr) + + def test_upgrade_with_revert(dut: DeviceAdapter, shell: Shell, mcumgr: MCUmgr): """ Verify that MCUboot will roll back an image that is not confirmed @@ -133,7 +141,7 @@ def test_upgrade_with_revert(dut: DeviceAdapter, shell: Shell, mcumgr: MCUmgr): mcumgr.reset_device() dut.connect() - output = dut.readlines_until('Launching primary slot application') + output = dut.readlines_until(WELCOME_STRING) upgrade_string_to_verify = get_upgrade_string_to_verify(dut.device_config.build_dir) match_lines(output, [ 'Swap type: test', @@ -148,7 +156,7 @@ def test_upgrade_with_revert(dut: DeviceAdapter, shell: Shell, mcumgr: MCUmgr): mcumgr.reset_device() dut.connect() - output = dut.readlines_until('Launching primary slot application') + output = dut.readlines_until(WELCOME_STRING) match_lines(output, [ 'Swap type: revert', upgrade_string_to_verify @@ -159,10 +167,8 @@ def test_upgrade_with_revert(dut: DeviceAdapter, shell: Shell, mcumgr: MCUmgr): @pytest.mark.parametrize( 'key_file', [None, 'root-ec-p256.pem'], - ids=[ - 'no_key', - 'invalid_key' - ]) + ids=['no_key', 'invalid_key'] +) def test_upgrade_signature(dut: DeviceAdapter, shell: Shell, mcumgr: MCUmgr, key_file): """ Verify that the application is not updated when app is not signed or signed with invalid key @@ -210,7 +216,7 @@ def test_upgrade_signature(dut: DeviceAdapter, shell: Shell, mcumgr: MCUmgr, key mcumgr.reset_device() dut.connect() - output = dut.readlines_until('Launching primary slot application') + output = dut.readlines_until(WELCOME_STRING) upgrade_string_to_verify = get_upgrade_string_to_verify(dut.device_config.build_dir) match_no_lines(output, [upgrade_string_to_verify]) match_lines(output, ['Image in the secondary slot is not valid']) diff --git a/tests/boot/with_mcumgr/pytest/test_upgrade_ble.py b/tests/boot/with_mcumgr/pytest/test_upgrade_ble.py new file mode 100755 index 00000000000..c6fabbf4763 --- /dev/null +++ b/tests/boot/with_mcumgr/pytest/test_upgrade_ble.py @@ -0,0 +1,16 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +from __future__ import annotations + +import logging + +from test_upgrade import run_upgrade_with_confirm +from twister_harness import DeviceAdapter, MCUmgrBle, Shell + +logger = logging.getLogger(__name__) + + +def test_upgrade_with_confirm_ble(mcumgr_ble: MCUmgrBle, dut: DeviceAdapter, shell: Shell): + """Verify that the application can be updated over BLE""" + run_upgrade_with_confirm(dut, shell, mcumgr_ble) diff --git a/tests/boot/with_mcumgr/src/main.c b/tests/boot/with_mcumgr/src/main.c deleted file mode 100644 index ac05fd8ff51..00000000000 --- a/tests/boot/with_mcumgr/src/main.c +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -/* Main entry point */ -int main(void) -{ - printk("Launching primary slot application on %s\n", CONFIG_BOARD); - return 0; -} diff --git a/tests/boot/with_mcumgr/sysbuild/mcuboot.conf b/tests/boot/with_mcumgr/sysbuild/mcuboot.conf deleted file mode 100644 index 69938a0f972..00000000000 --- a/tests/boot/with_mcumgr/sysbuild/mcuboot.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_MCUBOOT_LOG_LEVEL_INF=y diff --git a/tests/boot/with_mcumgr/testcase.yaml b/tests/boot/with_mcumgr/testcase.yaml index b4b23be1600..4871830e41e 100644 --- a/tests/boot/with_mcumgr/testcase.yaml +++ b/tests/boot/with_mcumgr/testcase.yaml @@ -22,6 +22,18 @@ tests: pytest_root: - "pytest/test_upgrade.py" + boot.with_mcumgr.test_upgrade_ble: + platform_allow: + - nrf52840dk/nrf52840 + integration_platforms: + - nrf52840dk/nrf52840 + extra_args: EXTRA_CONF_FILE="overlay-bt.conf" + harness: pytest + harness_config: + fixture: usb_hci + pytest_root: + - "pytest/test_upgrade_ble.py" + boot.with_mcumgr.test_downgrade_prevention: platform_allow: - nrf52840dk/nrf52840