scripts: pytest: improve plugin options
Add better description of available options and add actions which should help to prevent from passing invalid options to plugin. Signed-off-by: Piotr Golyzniak <piotr.golyzniak@nordicsemi.no>
This commit is contained in:
parent
a31b24372c
commit
eb672ddd0a
11 changed files with 102 additions and 109 deletions
|
@ -7,7 +7,6 @@ from __future__ import annotations
|
|||
import abc
|
||||
import logging
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from twister_harness.device.device_adapter import DeviceAdapter
|
||||
from twister_harness.device.utils import log_command, terminate_process
|
||||
|
@ -119,7 +118,7 @@ class NativeSimulatorAdapter(BinaryAdapterBase):
|
|||
|
||||
def generate_command(self) -> None:
|
||||
"""Set command to run."""
|
||||
self.command = [str(Path(self.device_config.build_dir) / 'zephyr' / 'zephyr.exe')]
|
||||
self.command = [str(self.device_config.build_dir / 'zephyr' / 'zephyr.exe')]
|
||||
|
||||
|
||||
class UnitSimulatorAdapter(BinaryAdapterBase):
|
||||
|
@ -127,7 +126,7 @@ class UnitSimulatorAdapter(BinaryAdapterBase):
|
|||
|
||||
def generate_command(self) -> None:
|
||||
"""Set command to run."""
|
||||
self.command = [str(Path(self.device_config.build_dir) / 'testbinary')]
|
||||
self.command = [str(self.device_config.build_dir / 'testbinary')]
|
||||
|
||||
|
||||
class CustomSimulatorAdapter(BinaryAdapterBase):
|
||||
|
|
|
@ -40,7 +40,7 @@ class DeviceAdapter(abc.ABC):
|
|||
self.command: list[str] = []
|
||||
self._west: str | None = None
|
||||
|
||||
self.handler_log_path: Path = Path(device_config.build_dir) / 'handler.log'
|
||||
self.handler_log_path: Path = device_config.build_dir / 'handler.log'
|
||||
self._log_files: list[Path] = [self.handler_log_path]
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
|
|
@ -37,9 +37,9 @@ class DeviceFactory:
|
|||
logger.debug('Get device type "%s"', name)
|
||||
try:
|
||||
return cls._devices[name]
|
||||
except KeyError as e:
|
||||
except KeyError as exc:
|
||||
logger.error('There is no device with name "%s"', name)
|
||||
raise TwisterHarnessException(f'There is no device with name "{name}"') from e
|
||||
raise TwisterHarnessException(f'There is no device with name "{name}"') from exc
|
||||
|
||||
|
||||
DeviceFactory.register_device_class('custom', CustomSimulatorAdapter)
|
||||
|
|
|
@ -34,7 +34,7 @@ class HardwareAdapter(DeviceAdapter):
|
|||
self._serial_pty_proc: subprocess.Popen | None = None
|
||||
self._serial_buffer: bytearray = bytearray()
|
||||
|
||||
self.device_log_path: Path = Path(device_config.build_dir) / 'device.log'
|
||||
self.device_log_path: Path = device_config.build_dir / 'device.log'
|
||||
self._log_files.append(self.device_log_path)
|
||||
|
||||
def generate_command(self) -> None:
|
||||
|
|
|
@ -6,7 +6,6 @@ from __future__ import annotations
|
|||
|
||||
import logging
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from twister_harness.device.fifo_handler import FifoHandler
|
||||
from twister_harness.device.binary_adapter import BinaryAdapterBase
|
||||
|
@ -19,7 +18,7 @@ logger = logging.getLogger(__name__)
|
|||
class QemuAdapter(BinaryAdapterBase):
|
||||
def __init__(self, device_config: DeviceConfig) -> None:
|
||||
super().__init__(device_config)
|
||||
qemu_fifo_file_path = Path(self.device_config.build_dir) / 'qemu-fifo'
|
||||
qemu_fifo_file_path = self.device_config.build_dir / 'qemu-fifo'
|
||||
self._fifo_connection: FifoHandler = FifoHandler(qemu_fifo_file_path, self.base_timeout)
|
||||
|
||||
def generate_command(self) -> None:
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
class TwisterHarnessException(Exception):
|
||||
"""General Twister harness exception."""
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ from __future__ import annotations
|
|||
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -26,65 +25,13 @@ def pytest_addoption(parser: pytest.Parser):
|
|||
'--twister-harness',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Activate Twister harness plugin'
|
||||
help='Activate Twister harness plugin.'
|
||||
)
|
||||
parser.addini(
|
||||
'twister_harness',
|
||||
'Activate Twister harness plugin',
|
||||
type='bool'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'-O',
|
||||
'--outdir',
|
||||
metavar='PATH',
|
||||
dest='output_dir',
|
||||
help='Output directory for logs. If not provided then use '
|
||||
'--build-dir path as default.'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--platform',
|
||||
help='Choose specific platform'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--device-type',
|
||||
choices=('native', 'qemu', 'hardware', 'unit', 'custom'),
|
||||
help='Choose type of device (hardware, qemu, etc.)'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--device-serial',
|
||||
help='Serial device for accessing the board '
|
||||
'(e.g., /dev/ttyACM0)'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--device-serial-baud',
|
||||
type=int,
|
||||
default=115200,
|
||||
help='Serial device baud rate (default 115200)'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--runner',
|
||||
help='use the specified west runner (pyocd, nrfjprog, etc)'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--device-id',
|
||||
help='ID of connected hardware device (for example 000682459367)'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--device-product',
|
||||
help='Product name of connected hardware device (for example "STM32 STLink")'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--device-serial-pty',
|
||||
metavar='PATH',
|
||||
help='Script for controlling pseudoterminal. '
|
||||
'E.g --device-testing --device-serial-pty=<script>'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--west-flash-extra-args',
|
||||
help='Extend parameters for west flash. '
|
||||
'E.g. --west-flash-extra-args="--board-id=foobar,--erase" '
|
||||
'will translate to "west flash -- --board-id=foobar --erase"'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--base-timeout',
|
||||
type=float,
|
||||
|
@ -95,26 +42,64 @@ def pytest_addoption(parser: pytest.Parser):
|
|||
)
|
||||
twister_harness_group.addoption(
|
||||
'--build-dir',
|
||||
dest='build_dir',
|
||||
metavar='PATH',
|
||||
help='Directory with built application.'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--binary-file',
|
||||
metavar='PATH',
|
||||
help='Path to file which should be flashed.'
|
||||
'--device-type',
|
||||
choices=('native', 'qemu', 'hardware', 'unit', 'custom'),
|
||||
help='Choose type of device (hardware, qemu, etc.).'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--platform',
|
||||
help='Name of used platform (qemu_x86, nrf52840dk_nrf52840, etc.).'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--device-serial',
|
||||
help='Serial device for accessing the board (e.g., /dev/ttyACM0).'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--device-serial-baud',
|
||||
type=int,
|
||||
default=115200,
|
||||
help='Serial device baud rate (default 115200).'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--runner',
|
||||
help='Use the specified west runner (pyocd, nrfjprog, etc.).'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--device-id',
|
||||
help='ID of connected hardware device (for example 000682459367).'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--device-product',
|
||||
help='Product name of connected hardware device (e.g. "STM32 STLink").'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--device-serial-pty',
|
||||
help='Script for controlling pseudoterminal.'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--west-flash-extra-args',
|
||||
help='Extend parameters for west flash. '
|
||||
'E.g. --west-flash-extra-args="--board-id=foobar,--erase" '
|
||||
'will translate to "west flash -- --board-id=foobar --erase".'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--pre-script',
|
||||
metavar='PATH'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--post-script',
|
||||
metavar='PATH'
|
||||
metavar='PATH',
|
||||
help='Script executed before flashing and connecting to serial.'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--post-flash-script',
|
||||
metavar='PATH'
|
||||
metavar='PATH',
|
||||
help='Script executed after flashing.'
|
||||
)
|
||||
twister_harness_group.addoption(
|
||||
'--post-script',
|
||||
metavar='PATH',
|
||||
help='Script executed after closing serial connection.'
|
||||
)
|
||||
|
||||
|
||||
|
@ -125,24 +110,31 @@ def pytest_configure(config: pytest.Config):
|
|||
if not (config.getoption('twister_harness') or config.getini('twister_harness')):
|
||||
return
|
||||
|
||||
validate_options(config)
|
||||
|
||||
if config.option.output_dir is None:
|
||||
config.option.output_dir = config.option.build_dir
|
||||
config.option.output_dir = _normalize_path(config.option.output_dir)
|
||||
|
||||
# create output directory if not exists
|
||||
os.makedirs(config.option.output_dir, exist_ok=True)
|
||||
_normalize_paths(config)
|
||||
_validate_options(config)
|
||||
|
||||
config.twister_harness_config = TwisterHarnessConfig.create(config) # type: ignore
|
||||
|
||||
|
||||
def validate_options(config: pytest.Config) -> None:
|
||||
"""Verify if user provided proper options"""
|
||||
# TBD
|
||||
def _validate_options(config: pytest.Config) -> None:
|
||||
if not config.option.build_dir:
|
||||
raise Exception('--build-dir has to be provided')
|
||||
if not os.path.isdir(config.option.build_dir):
|
||||
raise Exception(f'Provided --build-dir does not exist: {config.option.build_dir}')
|
||||
if not config.option.device_type:
|
||||
raise Exception('--device-type has to be provided')
|
||||
|
||||
|
||||
def _normalize_path(path: str | Path) -> str:
|
||||
path = os.path.expanduser(os.path.expandvars(path))
|
||||
path = os.path.normpath(os.path.abspath(path))
|
||||
def _normalize_paths(config: pytest.Config) -> None:
|
||||
"""Normalize paths provided by user via CLI"""
|
||||
config.option.build_dir = _normalize_path(config.option.build_dir)
|
||||
config.option.pre_script = _normalize_path(config.option.pre_script)
|
||||
config.option.post_script = _normalize_path(config.option.post_script)
|
||||
config.option.post_flash_script = _normalize_path(config.option.post_flash_script)
|
||||
|
||||
|
||||
def _normalize_path(path: str | None) -> str:
|
||||
if path is not None:
|
||||
path = os.path.expanduser(os.path.expandvars(path))
|
||||
path = os.path.normpath(os.path.abspath(path))
|
||||
return path
|
||||
|
|
|
@ -15,8 +15,10 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
@dataclass
|
||||
class DeviceConfig:
|
||||
type: str
|
||||
build_dir: Path
|
||||
base_timeout: float = 60.0 # [s]
|
||||
platform: str = ''
|
||||
type: str = ''
|
||||
serial: str = ''
|
||||
baud: int = 115200
|
||||
runner: str = ''
|
||||
|
@ -24,25 +26,20 @@ class DeviceConfig:
|
|||
product: str = ''
|
||||
serial_pty: str = ''
|
||||
west_flash_extra_args: list[str] = field(default_factory=list, repr=False)
|
||||
base_timeout: float = 60.0 # [s]
|
||||
build_dir: Path | str = ''
|
||||
binary_file: Path | str = ''
|
||||
name: str = ''
|
||||
pre_script: str = ''
|
||||
post_script: str = ''
|
||||
post_flash_script: str = ''
|
||||
pre_script: Path | None = None
|
||||
post_script: Path | None = None
|
||||
post_flash_script: Path | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class TwisterHarnessConfig:
|
||||
"""Store Twister harness configuration to have easy access in test."""
|
||||
output_dir: Path = Path('twister_harness_out')
|
||||
devices: list[DeviceConfig] = field(default_factory=list, repr=False)
|
||||
|
||||
@classmethod
|
||||
def create(cls, config: pytest.Config) -> TwisterHarnessConfig:
|
||||
"""Create new instance from pytest.Config."""
|
||||
output_dir: Path = config.option.output_dir
|
||||
|
||||
devices = []
|
||||
|
||||
|
@ -50,8 +47,10 @@ class TwisterHarnessConfig:
|
|||
if config.option.west_flash_extra_args:
|
||||
west_flash_extra_args = [w.strip() for w in config.option.west_flash_extra_args.split(',')]
|
||||
device_from_cli = DeviceConfig(
|
||||
platform=config.option.platform,
|
||||
type=config.option.device_type,
|
||||
build_dir=_cast_to_path(config.option.build_dir),
|
||||
base_timeout=config.option.base_timeout,
|
||||
platform=config.option.platform,
|
||||
serial=config.option.device_serial,
|
||||
baud=config.option.device_serial_baud,
|
||||
runner=config.option.runner,
|
||||
|
@ -59,17 +58,19 @@ class TwisterHarnessConfig:
|
|||
product=config.option.device_product,
|
||||
serial_pty=config.option.device_serial_pty,
|
||||
west_flash_extra_args=west_flash_extra_args,
|
||||
base_timeout=config.option.base_timeout,
|
||||
build_dir=config.option.build_dir,
|
||||
binary_file=config.option.binary_file,
|
||||
pre_script=config.option.pre_script,
|
||||
post_script=config.option.post_script,
|
||||
post_flash_script=config.option.post_flash_script,
|
||||
pre_script=_cast_to_path(config.option.pre_script),
|
||||
post_script=_cast_to_path(config.option.post_script),
|
||||
post_flash_script=_cast_to_path(config.option.post_flash_script),
|
||||
)
|
||||
|
||||
devices.append(device_from_cli)
|
||||
|
||||
return cls(
|
||||
output_dir=output_dir,
|
||||
devices=devices
|
||||
)
|
||||
|
||||
|
||||
def _cast_to_path(path: str | None) -> Path | None:
|
||||
if path is None:
|
||||
return None
|
||||
return Path(path)
|
||||
|
|
|
@ -20,7 +20,7 @@ from twister_harness.twister_harness_config import DeviceConfig
|
|||
|
||||
@pytest.fixture(name='device')
|
||||
def fixture_adapter(tmp_path) -> NativeSimulatorAdapter:
|
||||
return NativeSimulatorAdapter(DeviceConfig(build_dir=tmp_path))
|
||||
return NativeSimulatorAdapter(DeviceConfig(build_dir=tmp_path, type='native'))
|
||||
|
||||
|
||||
def test_if_simulator_adapter_runs_without_errors(
|
||||
|
@ -106,7 +106,7 @@ def test_if_native_simulator_adapter_get_command_returns_proper_string(
|
|||
|
||||
@mock.patch('shutil.which', return_value='west')
|
||||
def test_if_custom_simulator_adapter_get_command_returns_proper_string(patched_which, tmp_path: Path) -> None:
|
||||
device = CustomSimulatorAdapter(DeviceConfig(build_dir=tmp_path))
|
||||
device = CustomSimulatorAdapter(DeviceConfig(build_dir=tmp_path, type='custom'))
|
||||
device.generate_command()
|
||||
assert isinstance(device.command, list)
|
||||
assert device.command == ['west', 'build', '-d', str(tmp_path), '-t', 'run']
|
||||
|
@ -114,13 +114,13 @@ def test_if_custom_simulator_adapter_get_command_returns_proper_string(patched_w
|
|||
|
||||
@mock.patch('shutil.which', return_value=None)
|
||||
def test_if_custom_simulator_adapter_raise_exception_when_west_not_found(patched_which, tmp_path: Path) -> None:
|
||||
device = CustomSimulatorAdapter(DeviceConfig(build_dir=tmp_path))
|
||||
device = CustomSimulatorAdapter(DeviceConfig(build_dir=tmp_path, type='custom'))
|
||||
with pytest.raises(TwisterHarnessException, match='west not found'):
|
||||
device.generate_command()
|
||||
|
||||
|
||||
def test_if_unit_simulator_adapter_get_command_returns_proper_string(tmp_path: Path) -> None:
|
||||
device = UnitSimulatorAdapter(DeviceConfig(build_dir=tmp_path))
|
||||
device = UnitSimulatorAdapter(DeviceConfig(build_dir=tmp_path, type='unit'))
|
||||
device.generate_command()
|
||||
assert isinstance(device.command, list)
|
||||
assert device.command == [str(tmp_path / 'testbinary')]
|
||||
|
|
|
@ -18,6 +18,7 @@ def fixture_adapter(tmp_path) -> HardwareAdapter:
|
|||
build_dir = tmp_path / 'build_dir'
|
||||
os.mkdir(build_dir)
|
||||
device_config = DeviceConfig(
|
||||
type='hardware',
|
||||
runner='runner',
|
||||
build_dir=build_dir,
|
||||
platform='platform',
|
||||
|
|
|
@ -18,7 +18,7 @@ from twister_harness.twister_harness_config import DeviceConfig
|
|||
def fixture_device_adapter(tmp_path) -> Generator[QemuAdapter, None, None]:
|
||||
build_dir = tmp_path / 'build_dir'
|
||||
os.mkdir(build_dir)
|
||||
device = QemuAdapter(DeviceConfig(build_dir=build_dir))
|
||||
device = QemuAdapter(DeviceConfig(build_dir=build_dir, type='qemu'))
|
||||
try:
|
||||
yield device
|
||||
finally:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue