West: Add `west robot` command

Introduce `robot` command for running Robot Framework test suites.
Initial implementation consists of one runner dedicated for renode-test,
which is a Renode wrapper for running Robot tests.

Signed-off-by: Michał Szprejda <mszprejda@antmicro.com>
This commit is contained in:
Michał Szprejda 2024-03-07 10:35:06 +01:00 committed by Alberto Escolar
parent 80900cbc3b
commit 7c084b6649
12 changed files with 168 additions and 4 deletions

View File

@ -0,0 +1,17 @@
# SPDX-License-Identifier: Apache-2.0
board_set_robot_runner_ifnset(renode-robot)
# `--variable` is a renode-test argument, for setting a variable that can be later used in a .robot file:
# ELF: used in common.robot to set the `elf` variable in the default .resc script defined in board.cmake
# RESC: path to the .resc script, defined in board.cmake
# UART: default UART used by Robot in tests, defined in board.cmake
# KEYWORDS: path to common.robot, which contains common Robot keywords
# RESULTS_DIR: directory in which Robot artifacts will be generated after running a testsuite
board_runner_args(renode-robot "--renode-robot-arg=--variable=ELF:@${PROJECT_BINARY_DIR}/${KERNEL_ELF_NAME}")
board_runner_args(renode-robot "--renode-robot-arg=--variable=RESC:@${RENODE_SCRIPT}")
board_runner_args(renode-robot "--renode-robot-arg=--variable=UART:${RENODE_UART}")
board_runner_args(renode-robot "--renode-robot-arg=--variable=KEYWORDS:${ZEPHYR_BASE}/tests/robot/common.robot")
board_runner_args(renode-robot "--renode-robot-arg=--variable=RESULTS_DIR:${APPLICATION_BINARY_DIR}")
board_finalize_runner_args(renode-robot)

View File

@ -5,4 +5,6 @@ set(RENODE_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/support/m2gl025_miv.resc)
set(RENODE_UART sysbus.uart)
set_ifndef(BOARD_SIM_RUNNER renode)
set_ifndef(BOARD_ROBOT_RUNNER renode-robot)
include(${ZEPHYR_BASE}/boards/common/renode.board.cmake)
include(${ZEPHYR_BASE}/boards/common/renode_robot.board.cmake)

View File

@ -30,4 +30,6 @@ elseif("${BOARD_REVISION}" STREQUAL "B")
endif()
set_ifndef(BOARD_SIM_RUNNER renode)
set_ifndef(BOARD_ROBOT_RUNNER renode-robot)
include(${ZEPHYR_BASE}/boards/common/renode.board.cmake)
include(${ZEPHYR_BASE}/boards/common/renode_robot.board.cmake)

View File

@ -101,6 +101,10 @@ function(create_runners_yaml)
runners_yaml_append("\n# Default simulation runner if --runner is not given.")
runners_yaml_append("sim-runner: ${BOARD_SIM_RUNNER}")
endif()
if(DEFINED BOARD_ROBOT_RUNNER)
runners_yaml_append("\n# Default test runner if --runner is not given.")
runners_yaml_append("robot-runner: ${BOARD_ROBOT_RUNNER}")
endif()
# Sets up common runner configuration values.
runners_yaml_append_config()

View File

@ -705,7 +705,7 @@ endfunction()
# This section provides glue between CMake and the Python code that
# manages the runners.
set(TYPES "FLASH" "DEBUG" "SIM")
set(TYPES "FLASH" "DEBUG" "SIM" "ROBOT")
function(_board_check_runner_type type) # private helper
if (NOT "${type}" IN_LIST TYPES)
message(FATAL_ERROR "invalid type ${type}; should be one of: ${TYPES}")
@ -724,7 +724,7 @@ endfunction()
#
# This would set the board's flash runner to "pyocd".
#
# In general, "type" is FLASH, DEBUG or SIM and "runner" is
# In general, "type" is FLASH, DEBUG, SIM or ROBOT and "runner" is
# the name of a runner.
function(board_set_runner type runner)
_board_check_runner_type(${type})
@ -766,6 +766,11 @@ macro(board_set_debugger_ifnset runner)
board_set_runner_ifnset(DEBUG ${runner})
endmacro()
# A convenience macro for board_set_runner_ifnset(ROBOT ${runner}).
macro(board_set_robot_runner_ifnset runner)
board_set_runner_ifnset(ROBOT ${runner})
endmacro()
# A convenience macro for board_set_runner_ifnset(SIM ${runner}).
macro(board_set_sim_runner_ifnset runner)
board_set_runner_ifnset(SIM ${runner})

View File

@ -698,6 +698,44 @@ determined by the imported subclasses of ``ZephyrBinaryRunner``.
runner implementations are in other submodules, such as ``runners.nrfjprog``,
``runners.openocd``, etc.
Running Robot Framework tests: ``west robot``
*********************************************
.. tip:: Run ``west robot -h`` for additional help.
Basics
======
Currently the command supports only one runner which is using ``renode-test``,
(essentially a wrapper for running Robot tests in Renode), but can be
easily extended by adding other runners.
From a Zephyr build directory, to run a Robot test suite::
west robot --runner=renode-robot --testsuite path/to/testsuite.robot
This will run all tests from testsuite.robot and print output provided
by Robot Framework.
To pass additional parameters to Renode use ``--renode-robot-args`` switch.
For example to show Renode logs in addition to Robot Framework's output:
west robot --runner=renode-robot --testsuite path/to/testsuite.robot --renode-robot-arg="--show-log"
Runner-Specific Overrides
=========================
To view all of the available options for the Robot runners your board
supports, as well as their usage information, use ``--context`` (or
``-H``)::
west robot --runner=renode-robot --context
To view all available options "renode-test" runner supports, use::
west robot --runner=renode-robot --renode-robot-help
Simulating a board with: ``west simulate``
******************************************

View File

@ -66,6 +66,11 @@ west-commands:
- name: bindesc
class: Bindesc
help: work with Binary Descriptors
- file: scripts/west_commands/robot.py
commands:
- name: robot
class: Robot
help: run RobotFramework test suites
- file: scripts/west_commands/simulate.py
commands:
- name: simulate

View File

@ -0,0 +1,29 @@
# Copyright (c) 2024 Antmicro <www.antmicro.com>
#
# SPDX-License-Identifier: Apache-2.0
from west.commands import WestCommand
from run_common import add_parser_common, do_run_common
EXPORT_DESCRIPTION = '''\
Run RobotFramework test suites with a runner of choice.
'''
class Robot(WestCommand):
def __init__(self):
super(Robot, self).__init__(
'robot',
# Keep this in sync with the string in west-commands.yml.
'run RobotFramework test suites',
EXPORT_DESCRIPTION,
accepts_unknown_args=True)
self.runner_key = 'robot-runner' # in runners.yaml
def do_add_parser(self, parser_adder):
return add_parser_common(self, parser_adder)
def do_run(self, my_args, runner_args):
do_run_common(self, my_args, runner_args)

View File

@ -49,6 +49,7 @@ _names = [
'openocd',
'pyocd',
'renode',
'renode-robot',
'qemu',
'silabs_commander',
'spi_burn',

View File

@ -200,7 +200,7 @@ class MissingProgram(FileNotFoundError):
super().__init__(errno.ENOENT, os.strerror(errno.ENOENT), program)
_RUNNERCAPS_COMMANDS = {'flash', 'debug', 'debugserver', 'attach', 'simulate'}
_RUNNERCAPS_COMMANDS = {'flash', 'debug', 'debugserver', 'attach', 'simulate', 'robot'}
@dataclass
class RunnerCaps:
@ -212,7 +212,7 @@ class RunnerCaps:
Available capabilities:
- commands: set of supported commands; default is {'flash',
'debug', 'debugserver', 'attach', 'simulate'}.
'debug', 'debugserver', 'attach', 'simulate', 'robot'}.
- dev_id: whether the runner supports device identifiers, in the form of an
-i, --dev-id option. This is useful when the user has multiple debuggers

View File

@ -0,0 +1,60 @@
# Copyright (c) 2024 Antmicro <www.antmicro.com>
#
# SPDX-License-Identifier: Apache-2.0
'''Runner stub for renode-test.'''
import subprocess
from runners.core import ZephyrBinaryRunner, RunnerCaps
class RenodeRobotRunner(ZephyrBinaryRunner):
'''Place-holder for Renode runner customizations.'''
def __init__(self, cfg, args):
super().__init__(cfg)
self.testsuite = args.testsuite
self.renode_robot_arg = args.renode_robot_arg
self.renode_robot_help = args.renode_robot_help
@classmethod
def name(cls):
return 'renode-robot'
@classmethod
def capabilities(cls):
return RunnerCaps(commands={'robot'}, hide_load_files=True)
@classmethod
def do_add_parser(cls, parser):
parser.add_argument('--testsuite',
help='path to Robot test suite')
parser.add_argument('--renode-robot-arg',
metavar='ARG',
action='append',
help='additional argument passed to renode-test')
parser.add_argument('--renode-robot-help',
default=False,
action='store_true',
help='print all possible `renode-test` arguments')
@classmethod
def do_create(cls, cfg, args):
return RenodeRobotRunner(cfg, args)
def do_run(self, command, **kwargs):
self.run_test(**kwargs)
def run_test(self, **kwargs):
cmd = ['renode-test']
if self.renode_robot_help is True:
cmd.append('--help')
else:
if self.renode_robot_arg is not None:
for arg in self.renode_robot_arg:
cmd.append(arg)
if self.testsuite is not None:
cmd.append(self.testsuite)
else:
self.logger.error("No Robot testsuite passed to renode-test! Use the `--testsuite` argument to provide one.")
subprocess.run(cmd, check=True)

View File

@ -40,6 +40,7 @@ def test_runner_imports():
'pyocd',
'qemu',
'renode',
'renode-robot',
'silabs_commander',
'spi_burn',
'stm32cubeprogrammer',