forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
twister: Add robot framework integration
This change adds an entrypoint for the common robot framework and a first library to interact with the board, similar to the functionality currently available in pytest. To reuse the command line parsing and have a proper twister config, we provide a robot_wrapper which serializes the configuration and reloads it in the library. This change addresses zephyrproject-rtos#64825, which asks for robot scripts without renode. Signed-off-by: Stefan Kraus <[email protected]>
- Loading branch information
1 parent
baa8900
commit 6c50206
Showing
6 changed files
with
209 additions
and
0 deletions.
There are no files selected for viewing
57 changes: 57 additions & 0 deletions
57
scripts/pylib/pytest-twister-harness/src/twister_harness/robot_framework/ZephyrLibrary.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import pickle | ||
|
||
from robot.libraries.BuiltIn import BuiltIn | ||
from twister_harness import DeviceAdapter, Shell | ||
from twister_harness.device.factory import DeviceFactory | ||
from twister_harness.twister_harness_config import TwisterHarnessConfig | ||
|
||
|
||
class ZephyrLibrary: | ||
ROBOT_LIBRARY_SCOPE = "SUITE" | ||
|
||
def __init__(self): | ||
self.device: DeviceAdapter | None = None | ||
self.shell: Shell | None = None | ||
|
||
self.twister_harness_config = self._get_twister_harness_config() | ||
|
||
def _get_twister_harness_config(self) -> TwisterHarnessConfig: | ||
all_variables = BuiltIn().get_variables() | ||
twister_harness_config_file = all_variables.get( | ||
"${TWISTER_HARNESS_CONFIG_FILE}", None | ||
) | ||
if twister_harness_config_file is None: | ||
raise ValueError( | ||
"TWISTER_HARNESS_CONFIG_FILE variable must be set to file with pickle" | ||
) | ||
|
||
with open(twister_harness_config_file, "rb") as twister_harness_file: | ||
return pickle.load(twister_harness_file) | ||
|
||
def get_a_device(self): | ||
device_object = DeviceFactory.get_device_object(self.twister_harness_config) | ||
self.device = device_object | ||
return device_object | ||
|
||
def run_device(self): | ||
if self.device is None: | ||
raise ValueError("Currently no device") | ||
|
||
self.device.launch() | ||
|
||
def run_command(self, command: str) -> list[str]: | ||
if self.device is None: | ||
raise ValueError("Currently no device") | ||
|
||
if self.shell is None: | ||
self.shell = Shell(self.device) | ||
assert self.shell.wait_for_prompt() | ||
|
||
return self.shell.exec_command(command) | ||
|
||
def close_device(self): | ||
if self.device is None: | ||
raise ValueError("Currently no device") | ||
|
||
self.device.close() | ||
self.device = None |
Empty file.
46 changes: 46 additions & 0 deletions
46
scripts/pylib/pytest-twister-harness/src/twister_harness/robot_framework/robot_wrapper.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import argparse | ||
import pickle | ||
|
||
import robot | ||
from twister_harness.argument_handler import ArgumentHandler | ||
from twister_harness.twister_harness_config import TwisterHarnessConfig | ||
|
||
ROBOT_TWISTER_VAR_FILE = "robot_twister_var.pickle" | ||
|
||
|
||
def _parse_arguments(): | ||
parser = argparse.ArgumentParser() | ||
|
||
handler = ArgumentHandler(parser.add_argument) | ||
handler.add_common_arguments() | ||
|
||
options, rest_args = parser.parse_known_args() | ||
|
||
handler.sanitize_options(options) | ||
|
||
return options, rest_args | ||
|
||
|
||
def _serialize_config(twister_harness_config: TwisterHarnessConfig): | ||
device = twister_harness_config.devices[0] | ||
|
||
filepath = device.build_dir / ROBOT_TWISTER_VAR_FILE | ||
|
||
with open(device.build_dir / ROBOT_TWISTER_VAR_FILE, "wb") as robot_twister_vars: | ||
pickle.dump(twister_harness_config, robot_twister_vars) | ||
|
||
return filepath | ||
|
||
|
||
def main(): | ||
options, rest_args = _parse_arguments() | ||
twister_harness_config = TwisterHarnessConfig.create(options) | ||
variables_filepath = _serialize_config(twister_harness_config) | ||
|
||
robot.run_cli( | ||
["--variable", f"TWISTER_HARNESS_CONFIG_FILE:{variables_filepath}"] + rest_args | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
11 changes: 11 additions & 0 deletions
11
scripts/pylib/pytest-twister-harness/tests/robot_framework/device_test.robot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
*** Settings *** | ||
Documentation Robot testfile to check for existence of commands. | ||
Library twister_harness.robot_framework.ZephyrLibrary | ||
|
||
*** Test Cases *** | ||
Command workflow test | ||
[Documentation] Test that all commands exist. | ||
Get a Device | ||
Run Device | ||
Run Command echo 'my device' | ||
Close Device |
41 changes: 41 additions & 0 deletions
41
scripts/pylib/pytest-twister-harness/tests/robot_framework/robot_wrapper_test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import pathlib | ||
import sys | ||
from unittest.mock import patch | ||
|
||
import pytest | ||
from twister_harness.robot_framework import robot_wrapper | ||
|
||
|
||
def test__integration__dry_run_robotfile__no_errors(): | ||
robot_file = pathlib.Path(__file__).parent / "device_test.robot" | ||
cli_arguments = [ | ||
"twister_harness.robot_framework.robot_wrapper", | ||
"--quiet", | ||
"--dryrun", | ||
"--build-dir", | ||
".", | ||
"--device-type=custom", | ||
str(robot_file), | ||
] | ||
with patch.object(sys, "argv", cli_arguments): | ||
with pytest.raises(SystemExit) as excinfo: | ||
robot_wrapper.main() | ||
|
||
assert excinfo.value.code == 0 | ||
|
||
|
||
def test__integration__missing_parameter__raises_nonzero_systemexit(): | ||
robot_file = pathlib.Path(__file__).parent / "device_test.robot" | ||
cli_arguments = [ | ||
"twister_harness.robot_framework.robot_wrapper", | ||
"--quiet", | ||
"--dryrun", | ||
"--build-dir", | ||
".", | ||
"--device-type=custom", | ||
] | ||
with patch.object(sys, "argv", cli_arguments): | ||
with pytest.raises(SystemExit) as excinfo: | ||
robot_wrapper.main() | ||
|
||
assert excinfo.value.code != 0 |
54 changes: 54 additions & 0 deletions
54
scripts/pylib/pytest-twister-harness/tests/robot_framework/zephyr_library_test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import pathlib | ||
from unittest.mock import patch | ||
|
||
import pytest | ||
from twister_harness import DeviceAdapter | ||
from twister_harness.device.binary_adapter import NativeSimulatorAdapter | ||
from twister_harness.robot_framework.ZephyrLibrary import ZephyrLibrary | ||
from twister_harness.twister_harness_config import DeviceConfig, TwisterHarnessConfig | ||
|
||
|
||
@pytest.fixture | ||
def twister_harness_config(tmp_path): | ||
device_config = DeviceConfig(type="custom", build_dir=tmp_path) | ||
twister_harness_config = TwisterHarnessConfig() | ||
twister_harness_config.devices = [device_config] | ||
yield twister_harness_config | ||
|
||
|
||
@pytest.fixture | ||
def zephyr_library(twister_harness_config): | ||
with patch.object( | ||
ZephyrLibrary, | ||
"_get_twister_harness_config", | ||
return_value=twister_harness_config, | ||
): | ||
yield ZephyrLibrary() | ||
|
||
|
||
def test__init__correctly_initialized(zephyr_library, twister_harness_config): | ||
assert zephyr_library.device is None | ||
assert zephyr_library.shell is None | ||
assert zephyr_library is not None | ||
|
||
assert zephyr_library.twister_harness_config == twister_harness_config | ||
|
||
|
||
def test__run_device__correctly_setup( | ||
zephyr_library, shell_simulator_adapter: NativeSimulatorAdapter | ||
): | ||
zephyr_library.device = shell_simulator_adapter | ||
|
||
zephyr_library.run_device() | ||
|
||
|
||
def test__run_command__can_execute_commands( | ||
zephyr_library, shell_simulator_adapter: NativeSimulatorAdapter | ||
): | ||
zephyr_library.device = shell_simulator_adapter | ||
|
||
zephyr_library.run_device() | ||
result = zephyr_library.run_command("zen") | ||
|
||
assert result is not None | ||
assert isinstance(result, list) |