Skip to content

Commit c6b3b93

Browse files
gchwierkartben
authored andcommitted
twister: pytest: Add support for mcumgr go tool with BLE
Added basic support to run upgrade with mcumgr tool using BLE transport. Signed-off-by: Grzegorz Chwierut <grzegorz.chwierut@nordicsemi.no>
1 parent ba905d0 commit c6b3b93

File tree

3 files changed

+56
-8
lines changed

3 files changed

+56
-8
lines changed

scripts/pylib/pytest-twister-harness/src/twister_harness/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
# flake8: noqa
66

77
from twister_harness.device.device_adapter import DeviceAdapter
8-
from twister_harness.helpers.mcumgr import MCUmgr
8+
from twister_harness.helpers.mcumgr import MCUmgr, MCUmgrBle
99
from twister_harness.helpers.shell import Shell
1010

11-
__all__ = ['DeviceAdapter', 'MCUmgr', 'Shell']
11+
__all__ = ['DeviceAdapter', 'MCUmgr', 'MCUmgrBle', 'Shell']
1212

1313
__version__ = '0.0.1'

scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from twister_harness.device.factory import DeviceFactory
1414
from twister_harness.twister_harness_config import DeviceConfig, TwisterHarnessConfig
1515
from twister_harness.helpers.shell import Shell
16-
from twister_harness.helpers.mcumgr import MCUmgr
16+
from twister_harness.helpers.mcumgr import MCUmgr, MCUmgrBle
1717
from twister_harness.helpers.utils import find_in_config
1818

1919
logger = logging.getLogger(__name__)
@@ -46,14 +46,17 @@ def determine_scope(fixture_name, config):
4646

4747

4848
@pytest.fixture(scope=determine_scope)
49-
def unlaunched_dut(request: pytest.FixtureRequest, device_object: DeviceAdapter) -> Generator[DeviceAdapter, None, None]:
49+
def unlaunched_dut(
50+
request: pytest.FixtureRequest, device_object: DeviceAdapter
51+
) -> Generator[DeviceAdapter, None, None]:
5052
"""Return device object - with logs connected, but not run"""
5153
device_object.initialize_log_files(request.node.name)
5254
try:
5355
yield device_object
5456
finally: # to make sure we close all running processes execution
5557
device_object.close()
5658

59+
5760
@pytest.fixture(scope=determine_scope)
5861
def dut(request: pytest.FixtureRequest, device_object: DeviceAdapter) -> Generator[DeviceAdapter, None, None]:
5962
"""Return launched device - with run application."""
@@ -83,12 +86,34 @@ def shell(dut: DeviceAdapter) -> Shell:
8386
return shell
8487

8588

86-
@pytest.fixture(scope='session')
87-
def is_mcumgr_available() -> None:
89+
@pytest.fixture()
90+
def mcumgr(device_object: DeviceAdapter) -> Generator[MCUmgr, None, None]:
91+
"""Fixture to create an MCUmgr instance for serial connection."""
8892
if not MCUmgr.is_available():
8993
pytest.skip('mcumgr not available')
94+
yield MCUmgr.create_for_serial(device_object.device_config.serial)
9095

9196

9297
@pytest.fixture()
93-
def mcumgr(is_mcumgr_available: None, dut: DeviceAdapter) -> Generator[MCUmgr, None, None]:
94-
yield MCUmgr.create_for_serial(dut.device_config.serial)
98+
def mcumgr_ble(device_object: DeviceAdapter) -> Generator[MCUmgrBle, None, None]:
99+
"""Fixture to create an MCUmgr instance for BLE connection."""
100+
if not MCUmgrBle.is_available():
101+
pytest.skip('mcumgr for ble not available')
102+
103+
for fixture in device_object.device_config.fixtures:
104+
if fixture.startswith('usb_hci:'):
105+
hci_name = fixture.split(':', 1)[1]
106+
break
107+
else:
108+
pytest.skip('usb_hci fixture not found')
109+
110+
try:
111+
hci_index = int(hci_name.split('hci')[-1])
112+
except ValueError:
113+
pytest.skip(f'Invalid HCI name: {hci_name}. Expected format is "hciX".')
114+
115+
peer_name = find_in_config(
116+
Path(device_object.device_config.app_build_dir) / 'zephyr' / '.config', 'CONFIG_BT_DEVICE_NAME'
117+
) or 'Zephyr'
118+
119+
yield MCUmgrBle.create_for_ble(hci_index, peer_name)

scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/mcumgr.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
from __future__ import annotations
55

66
import logging
7+
import os
78
import re
89
import shlex
10+
import shutil
911
from dataclasses import dataclass
1012
from pathlib import Path
1113
from subprocess import check_output, getstatusoutput
@@ -113,3 +115,24 @@ def image_confirm(self, hash: str | None = None):
113115
if not hash:
114116
hash = self.get_hash_to_confirm()
115117
self.run_command(f'image confirm {hash}')
118+
119+
120+
class MCUmgrBle(MCUmgr):
121+
"""MCUmgr wrapper for BLE connection"""
122+
123+
@classmethod
124+
def create_for_ble(cls, hci_index: int, peer_name: str) -> MCUmgr:
125+
"""Create MCUmgr instance for BLE connection"""
126+
connection_string = (
127+
f'--conntype ble --hci {hci_index} '
128+
f'--connstring peer_name="{peer_name}"'
129+
)
130+
return cls(connection_options=connection_string)
131+
132+
@classmethod
133+
def is_available(cls) -> bool:
134+
"""Check if mcumgr is available. For BLE, it requires root privileges."""
135+
if os.getuid() != 0 and 'sudo' not in cls.mcumgr_exec:
136+
mcumgr_path = shutil.which(cls.mcumgr_exec)
137+
cls.mcumgr_exec = f'sudo {mcumgr_path}'
138+
return super().is_available()

0 commit comments

Comments
 (0)