Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
common --registry=https://bcr.bazel.build

test --test_output=errors


build:qemu-integration --run_under=//scripts:run_under_qemu
build:qemu-integration --test_arg="--qemu"
build:qemu-integration --test_arg="--os=qnx"
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@ MODULE.bazel.lock
.ruff_cache

bazel-*

# VS Code
.vscode

# Python cache/venv folders
*__pycache__*
.venv/
*.egg-info/
9 changes: 8 additions & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# *******************************************************************************
module(
name = "score_itf",
version = "0.1",
version = "0.1.0",
compatibility_level = 0,
)

Expand Down Expand Up @@ -72,6 +72,13 @@ git_override(
###############################################################################
bazel_dep(name = "rules_cc", version = "0.1.1")

###############################################################################
#
# Shell dependency
#
###############################################################################
bazel_dep(name = "rules_shell", version = "0.6.0")

################################################################################
#
# Load DLT dependencies
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Steps:
```
$ bazel test //test:test_ssh_bridge_network --test_output=streamed
```
* Note: If it fails check IP Address of started Qemu with `ifconfig` and update IP addresses in `itf/config/target_config.json` for `S_CORE_ECU_QEMU_BRIDGE_NETWORK`
* Note: If it fails, check `IP address set to:` in logs of started Qemu and update IP addresses in `itf/config/target_config.json` for `S_CORE_ECU_QEMU_BRIDGE_NETWORK`
* Run ssh test with qemu started with port forwarding
* Start Qemu with bridge network from `reference_integration/qnx_qemu` folder:
```
Expand Down
47 changes: 36 additions & 11 deletions bazel/py_itf_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,54 @@

load("@itf_pip//:requirements.bzl", "requirement")
load("@rules_python//python:defs.bzl", "py_test")
load("@score_itf//bazel/rules:run_as_exec.bzl", "test_as_exec")

def py_itf_test(name, srcs, args = [], data = [], plugins = [], **kwargs):
"""Bazel macro for running ITF tests.

Args:
name: Name of the test target.
srcs: List of source files for the test.
args: Additional arguments to pass to ITF.
data: Data files needed for the test.
plugins: List of pytest plugins to enable.
**kwargs: Additional keyword arguments passed to py_test.
"""
pytest_bootstrap = Label("@score_itf//:main.py")
pytest_ini = Label("@score_itf//:pytest.ini")
dlt_receive = Label("@score_itf//itf/plugins/dlt:dlt-receive_as_host")
dlt_library = Label("@score_itf//itf/plugins/dlt:libdlt_as_host.so")

data_as_exec = [pytest_ini] + srcs

if "itf.plugins.base.base_plugin" in plugins:
data_as_exec += [dlt_receive, dlt_library]
args.append("--dlt_receive_path=$(location %s)" % dlt_receive)

plugins = ["-p %s" % plugin for plugin in plugins]

py_test(
name = name,
name = "_" + name,
srcs = [
pytest_bootstrap,
] + srcs,
main = pytest_bootstrap,
deps = [
requirement("docker"),
requirement("pytest"),
requirement("paramiko"),
requirement("typing-extensions"),
requirement("netifaces"),
"@score_itf//:itf",
],
tags = ["manual"],
)

test_as_exec(
name = name,
executable = "_" + name,
data_as_exec = data_as_exec,
data = data,
args = args +
["-c $(location %s)" % pytest_ini] +
[
Expand All @@ -35,16 +70,6 @@ def py_itf_test(name, srcs, args = [], data = [], plugins = [], **kwargs):
] +
plugins +
["$(location %s)" % x for x in srcs],
deps = [
requirement("docker"),
requirement("pytest"),
requirement("paramiko"),
requirement("typing-extensions"),
"@score_itf//:itf",
],
data = [
pytest_ini,
] + data,
env = {
"PYTHONDONOTWRITEBYTECODE": "1",
},
Expand Down
File renamed without changes.
104 changes: 104 additions & 0 deletions bazel/rules/run_as_exec.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# *******************************************************************************
# Copyright (c) 2025 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

"""
Runs an executable on execution platform, with runtime deps built with either
target or execution platform configuration.

Executable rule outputs a symlink to the actual executable, fully leveraging
it's implementation (e.g. reuse a py_binary) and remaining somewhat OS
independent.

NOTE: This has one caveat, that the symlink is "built" with target
configuration. So do not depend on targets output by this rule unless
you're qualified personnel.
"""

def run_as_exec(**kwargs):
"""This macro remaps the arguments for clarity:

deps -> data_as_exec: Runtime deps built with execution platform configuration.
"""
data_as_exec = kwargs.pop("data_as_exec", None)
_as_exec_run(
deps = data_as_exec,
**kwargs
)

def test_as_exec(**kwargs):
"""This macro remaps the arguments for clarity:

deps -> data_as_exec: Runtime deps built with execution platform configuration.
"""
data_as_exec = kwargs.pop("data_as_exec", None)
_as_exec_test(
deps = data_as_exec,
**kwargs
)

_RULE_ATTRS = {
# In order for args expansion to work in bazel for an executable rule
# the attributes must be one of: "srcs", "deps", "data" or "tools".
# See Bazel's LocationExpander implementation, these attribute names
# are hardcoded.
"data": attr.label_list(
allow_files = True,
cfg = "target",
),
"deps": attr.label_list(
allow_files = True,
cfg = "exec",
),
"env": attr.string_dict(),
"executable": attr.label(
allow_files = True,
cfg = "exec",
executable = True,
mandatory = True,
),
}

def _executable_as_exec_impl(ctx):
link = ctx.actions.declare_file(ctx.attr.name)
ctx.actions.symlink(
output = link,
target_file = ctx.executable.executable,
is_executable = True,
)

return [
DefaultInfo(
executable = link,
runfiles = ctx.runfiles(
files = ctx.files.data + ctx.files.deps + ctx.files.executable,
transitive_files = depset(
transitive = [ctx.attr.executable.default_runfiles.files] +
[dataf.default_runfiles.files for dataf in ctx.attr.data] +
[dataf.data_runfiles.files for dataf in ctx.attr.data],
),
),
),
RunEnvironmentInfo(environment = ctx.attr.env),
]

_as_exec_run = rule(
implementation = _executable_as_exec_impl,
attrs = _RULE_ATTRS,
executable = True,
)

_as_exec_test = rule(
implementation = _executable_as_exec_impl,
attrs = _RULE_ATTRS,
test = True,
)
8 changes: 6 additions & 2 deletions config/target_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"data_router_config": {
"vlan_address": "127.0.0.1",
"multicast_addresses": []
}
},
"qemu_num_cores": 2,
"qemu_ram_size": "1G"
},
"safety_processor": {
"name": "S_CORE_ECU_QEMU_BRIDGE_NETWORK_SC",
Expand All @@ -39,7 +41,9 @@
"data_router_config": {
"vlan_address": "127.0.0.1",
"multicast_addresses": []
}
},
"qemu_num_cores": 2,
"qemu_ram_size": "1G"
},
"safety_processor": {
"name": "CORE_ECU_QEMU_PORT_FORWARDING_SC",
Expand Down
13 changes: 13 additions & 0 deletions examples/MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ register_toolchains("@llvm_toolchain//:all")
###############################################################################
bazel_dep(name = "rules_cc", version = "0.1.1")

###############################################################################
#
# Shell dependency
#
###############################################################################
bazel_dep(name = "rules_shell", version = "0.6.0")

###############################################################################
#
# Container dependencies
Expand Down Expand Up @@ -79,6 +86,12 @@ bazel_dep(name = "rules_pkg", version = "1.0.1")
#
###############################################################################
bazel_dep(name = "googletest", version = "1.15.0")

###############################################################################
#
# ITF dependency
#
###############################################################################
bazel_dep(name = "score_itf", version = "0.1")
local_path_override(
module_name = "score_itf",
Expand Down
12 changes: 12 additions & 0 deletions itf/plugins/base/base_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ def pytest_addoption(parser):
default="config/target_config.json",
help="Path to json file with target configurations.",
)
# Internally provided in py_itf_test macro
parser.addoption(
"--dlt_receive_path",
action="store",
help="Path to dlt-receive binary",
)
parser.addoption(
"--ecu",
action="store",
Expand All @@ -52,6 +58,8 @@ def pytest_addoption(parser):
help="Operating System to run",
)
parser.addoption("--qemu", action="store_true", help="Run tests with QEMU image")
parser.addoption("--qemu_image", action="store", help="Path to a QEMU image")

parser.addoption("--qvp", action="store_true", help="Run tests with QVP")
parser.addoption("--hw", action="store_true", help="Run tests against connected HW")

Expand Down Expand Up @@ -115,11 +123,15 @@ def __make_test_config(config):
ecu=target_ecu_argparse(config.getoption("ecu")),
os=config.getoption("os"),
qemu=config.getoption("qemu"),
qemu_image=config.getoption("qemu_image"),
qvp=config.getoption("qvp"),
hw=config.getoption("hw"),
dlt_receive_path=config.getoption("dlt_receive_path"),
)


def __make_target_config(test_config):
target_config = test_config.ecu.sut
if test_config.qemu_image:
target_config.qemu_image_path = test_config.qemu_image
return target_config
1 change: 1 addition & 0 deletions itf/plugins/base/target/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ py_library(
"//itf/plugins/base/target/config",
"//itf/plugins/base/target/processors",
"//itf/plugins/dlt",
"//itf/plugins/qemu",
],
)
2 changes: 2 additions & 0 deletions itf/plugins/base/target/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ def load_configuration(config_file: str):
network_interfaces=perf_config["network_interfaces"],
ecu_name=perf_config["ecu_name"],
data_router_config=perf_config["data_router_config"],
qemu_num_cores=perf_config["qemu_num_cores"],
qemu_ram_size=perf_config["qemu_ram_size"],
params=perf_config.get("params", {}),
)
PERFORMANCE_PROCESSORS[perf_config["name"]] = performance_processor
Expand Down
26 changes: 26 additions & 0 deletions itf/plugins/base/target/config/performance_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ def __init__(
network_interfaces: list = [],
ecu_name: str = None,
data_router_config: dict = None,
qemu_num_cores: int = 2,
qemu_ram_size: str = "1G",
params: dict = None,
):
"""Initialize the PerformanceProcessor class.
Expand All @@ -42,6 +44,8 @@ def __init__(
:param str ecu_name: The ECU name for the processor.
:param dict data_router_configs: Configuration for the data router
with keys "vlan_address" and "multicast_addresses".
:param int qemu_num_cores: The number of CPU cores for QEMU.
:param str qemu_ram_size: The amount of RAM for QEMU.
:param dict params: Additional parameters for the processor.
"""
super().__init__(
Expand All @@ -57,6 +61,9 @@ def __init__(
self.__network_interfaces = network_interfaces
self.__ecu_name = ecu_name
self.__data_router_config = data_router_config
self.__qemu_num_cores = qemu_num_cores
self.__qemu_ram_size = qemu_ram_size
self.__qemu_image_path = None

@property
def ext_ip_address(self):
Expand All @@ -74,6 +81,22 @@ def network_interfaces(self):
def data_router_config(self):
return self.__data_router_config

@property
def qemu_num_cores(self):
return self.__qemu_num_cores

@property
def qemu_ram_size(self):
return self.__qemu_ram_size

@property
def qemu_image_path(self):
return self.__qemu_image_path

@qemu_image_path.setter
def qemu_image_path(self, value):
self.__qemu_image_path = value

def update(self, processor):
"""Update the current processor with another processor's parameters.

Expand All @@ -84,6 +107,9 @@ def update(self, processor):
self.__network_interfaces = processor.network_interfaces
self.__ecu_name = processor.ecu_name
self.__data_router_config = processor.data_router_config
self.__qemu_num_cores = processor.num_cores
self.__qemu_ram_size = processor.ram_size
self.__qemu_image_path = processor.qemu_image_path

def __eq__(self, other):
if isinstance(other, PerformanceProcessor):
Expand Down
Loading