diff --git a/doc/develop/test/pytest.rst b/doc/develop/test/pytest.rst index 9bf95c030989..88137a691747 100644 --- a/doc/develop/test/pytest.rst +++ b/doc/develop/test/pytest.rst @@ -219,6 +219,8 @@ Shell .. automethod:: wait_for_prompt + .. automethod:: get_filtered_output + Examples of pytest tests in the Zephyr project ********************************************** diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py index 7782617538c7..0960db7743ae 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py @@ -22,7 +22,9 @@ class Shell: Helper class that provides methods used to interact with shell application. """ - def __init__(self, device: DeviceAdapter, prompt: str = 'uart:~$', timeout: float | None = None) -> None: + def __init__( + self, device: DeviceAdapter, prompt: str = 'uart:~$', timeout: float | None = None + ) -> None: self._device: DeviceAdapter = device self.prompt: str = prompt self.base_timeout: float = timeout or device.base_timeout @@ -48,7 +50,9 @@ def wait_for_prompt(self, timeout: float | None = None) -> bool: return True return False - def exec_command(self, command: str, timeout: float | None = None, print_output: bool = True) -> list[str]: + def exec_command( + self, command: str, timeout: float | None = None, print_output: bool = True + ) -> list[str]: """ Send shell command to a device and return response. Passed command is extended by double enter sings - first one to execute this command @@ -63,20 +67,42 @@ def exec_command(self, command: str, timeout: float | None = None, print_output: self._device.write(command_ext.encode()) lines: list[str] = [] # wait for device command print - it should be done immediately after sending command to device - lines.extend(self._device.readlines_until(regex=regex_command, timeout=1.0, print_output=print_output)) + lines.extend( + self._device.readlines_until( + regex=regex_command, timeout=1.0, print_output=print_output + ) + ) # wait for device command execution - lines.extend(self._device.readlines_until(regex=regex_prompt, timeout=timeout, print_output=print_output)) + lines.extend( + self._device.readlines_until( + regex=regex_prompt, timeout=timeout, print_output=print_output + ) + ) return lines def get_filtered_output(self, command_lines: list[str]) -> list[str]: + """ + Filter out prompts and log messages + + Take the output of exec_command, which can contain log messages and command prompts, + and filter them to obtain only the command output. + + Example: + >>> # equivalent to `lines = shell.exec_command("kernel version")` + >>> lines = [ + >>> 'uart:~$', # filter prompts + >>> 'Zephyr version 3.6.0', # keep this line + >>> 'uart:~$ debug message' # filter log messages + >>> ] + >>> filtered_output = shell.get_filtered_output(output) + >>> filtered_output + ['Zephyr version 3.6.0'] + + :param command_lines: List of strings i.e. the output of `exec_command`. + :return: A list of strings containing, excluding prompts and log messages. + """ regex_filter = re.compile( - '|'.join([ - re.escape(self.prompt), - '', - '', - '', - '' - ]) + '|'.join([re.escape(self.prompt), '', '', '', '']) ) return list(filter(lambda l: not regex_filter.search(l), command_lines)) @@ -106,6 +132,7 @@ class ShellMCUbootCommandParsed: """ Helper class to keep data from `mcuboot` shell command. """ + areas: list[ShellMCUbootArea] = field(default_factory=list) @classmethod