Skip to content
Open
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
61 changes: 61 additions & 0 deletions feature_integration_tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,66 @@ bazel test //feature_integration_tests/test_cases:fit_rust
bazel test --config=linux-x86_64 //feature_integration_tests/test_cases:fit_cpp
```

The Rust side of this lifecycle-only suite uses a dedicated Bazel target,
`//feature_integration_tests/test_scenarios/rust:rust_lifecycle_test_scenarios`,
which still reuses `test_scenarios/rust/src/main.rs`. It is built with the
`lifecycle_only` cfg so only lifecycle scenarios are compiled for that suite,
while the normal `fit` and `fit_rust` targets continue to use the full scenario tree.

To run the lifecycle tests directly with `pytest` and build the scenario binaries on demand:

```sh
python3 -m pytest feature_integration_tests/test_cases/tests/lifecycle/ \
--build-scenarios \
-m rust \
--rust-target-name=//feature_integration_tests/test_scenarios/rust:rust_lifecycle_test_scenarios \
-q -v

python3 -m pytest feature_integration_tests/test_cases/tests/lifecycle/ \
--build-scenarios \
-m cpp \
-q -v
```

The Rust override is required because plain `--build-scenarios` defaults to
`//feature_integration_tests/test_scenarios/rust:rust_test_scenarios`, while the
lifecycle tests need the reduced lifecycle-only Rust target.

#### Sandbox uid/gid and scheduling-policy tests

Some lifecycle daemon tests (e.g. `test_launched_process_uid_gid_matches_config_when_applied`,
`test_launched_process_scheduling_matches_config_when_applied`) verify that `launch_manager`
applies the sandbox `uid`/`gid` and scheduling policy from
`feature_integration_tests/configs/lifecycle_daemon_config.json`. This requires granting
`launch_manager` the `cap_setuid,cap_setgid,cap_sys_nice` file capabilities via `setcap`, which
in turn requires `CAP_SETFCAP` — not available to a non-root test runner by default.

Set `FIT_ENABLE_SETCAP=1` to opt in to a `sudo -n setcap` attempt (backed by a passwordless
sudoers rule scoped to the `setcap` binary, e.g. `<user> ALL=(root) NOPASSWD: /usr/sbin/setcap`,
with no trailing arguments pinned — the target path is a fresh `tmp_path` on every run). Without
it, these tests skip with a message identifying the missing capability grant.

```sh
export FIT_ENABLE_SETCAP=1

python3 -m pytest feature_integration_tests/test_cases/tests/lifecycle/ \
--build-scenarios \
-m cpp \
-k "uid_gid or scheduling" \
-q -v
```

Under `bazel test`, undeclared env vars like `FIT_ENABLE_SETCAP` do not reach the test process
unless passed via `--test_env` (not `--action_env`, which only affects build actions):

```sh
bazel test --config=linux-x86_64 //feature_integration_tests/test_cases:fit_cpp \
--test_env=FIT_ENABLE_SETCAP=1
```

`bazel run` inherits the invoking shell's environment directly, so exporting the variable
beforehand is sufficient there.

### ITF Tests (QEMU-based)

ITF tests run on a QEMU target and require the `itf-qnx-x86_64` config:
Expand All @@ -50,6 +110,7 @@ Test scenarios can be listed and run directly for debugging:

```sh
bazel run //feature_integration_tests/test_scenarios/rust:rust_test_scenarios -- --list-scenarios
bazel run //feature_integration_tests/test_scenarios/rust:rust_lifecycle_test_scenarios -- --list-scenarios
bazel run --config=linux-x86_64 //feature_integration_tests/test_scenarios/cpp:cpp_test_scenarios -- --list-scenarios
```

Expand Down
10 changes: 10 additions & 0 deletions feature_integration_tests/configs/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************
load("@score_lifecycle_health//:defs.bzl", "launch_manager_config")

exports_files(
[
"dlt_config_qnx_x86_64.json",
"dlt_config_x86_64.json",
"qemu_bridge_config.json",
"lifecycle_daemon_config.json",
],
)

Expand All @@ -31,3 +34,10 @@ filegroup(
],
visibility = ["//visibility:public"],
)

launch_manager_config(
name = "lifecycle_daemon_config",
config = ":lifecycle_daemon_config.json",
flatbuffer_out_dir = "etc",
visibility = ["//visibility:public"],
)
103 changes: 103 additions & 0 deletions feature_integration_tests/configs/lifecycle_daemon_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"schema_version": 1,
"defaults": {
"deployment_config": {
"bin_dir": "/tmp/lifecycle_fit/bin",
"ready_timeout": 2.0,
"shutdown_timeout": 2.0,
"ready_recovery_action": {
"restart": {
"number_of_attempts": 0
}
},
"recovery_action": {
"switch_run_target": {
"run_target": "fallback_run_target"
}
},
"sandbox": {
"uid": 1001,
"gid": 1001,
"scheduling_policy": "SCHED_OTHER",
"scheduling_priority": 0
}
},
"component_properties": {
"application_profile": {
"application_type": "Reporting",
"is_self_terminating": false,
"alive_supervision": {
"reporting_cycle": 0.1,
"min_indications": 1,
"max_indications": 3,
"failed_cycles_tolerance": 1
}
},
"ready_condition": {
"process_state": "Running"
}
}
},
"components": {
"cpp_supervised_app": {
"component_properties": {
"binary_name": "cpp_supervised_app",
"application_profile": {
"application_type": "Reporting_And_Supervised"
},
"process_arguments": [
"-d50"
]
},
"deployment_config": {
"environmental_variables": {
"PROCESSIDENTIFIER": "cpp_supervised_app",
"IDENTIFIER": "cpp_supervised_app"
}
}
},
"rust_supervised_app": {
"component_properties": {
"binary_name": "rust_supervised_app",
"depends_on": [
"cpp_supervised_app"
],
"application_profile": {
"application_type": "Reporting_And_Supervised"
},
"process_arguments": [
"-d50"
]
},
"deployment_config": {
"environmental_variables": {
"PROCESSIDENTIFIER": "rust_supervised_app",
"IDENTIFIER": "rust_supervised_app"
}
}
}
},
"run_targets": {
"Startup": {
"depends_on": [
"cpp_supervised_app",
"rust_supervised_app"
],
"recovery_action": {
"switch_run_target": {
"run_target": "fallback_run_target"
}
}
}
},
"initial_run_target": "Startup",
"alive_supervision": {
"evaluation_cycle": 0.05
},
"fallback_run_target": {
"depends_on": [
"cpp_supervised_app",
"rust_supervised_app"
]
}
}
124 changes: 120 additions & 4 deletions feature_integration_tests/test_cases/BUILD
Comment thread
Saumya-R marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ compile_pip_requirements(
)

# Tests targets
#
score_py_pytest(
name = "fit_rust",
srcs = glob(["tests/**/*.py"]),
name = "fit_rust_orch",
timeout = "long",
srcs = glob(["tests/basic/**/*.py"]),
args = [
"-m rust",
"--traces=all",
Expand All @@ -58,8 +60,78 @@ score_py_pytest(
)

score_py_pytest(
name = "fit_cpp",
srcs = glob(["tests/**/*.py"]),
name = "fit_rust_persistency",
timeout = "long",
srcs = glob(["tests/persistency/**/*.py"]),
args = [
"-m rust",
"--traces=all",
"--rust-target-path=$(rootpath //feature_integration_tests/test_scenarios/rust:rust_test_scenarios)",
],
data = [
"conftest.py",
"fit_scenario.py",
"persistency_scenario.py",
"test_properties.py",
"//feature_integration_tests/test_scenarios/rust:rust_test_scenarios",
],
env = {
"RUST_BACKTRACE": "1",
},
pytest_config = "//:pyproject.toml",
deps = all_requirements,
)

score_py_pytest(
name = "fit_rust_lifecycle",
timeout = "long",
srcs = glob(["tests/lifecycle/**/*.py"]),
args = [
"-m rust",
"--traces=all",
"--rust-target-path=$(rootpath //feature_integration_tests/test_scenarios/rust:rust_lifecycle_test_scenarios)",
],
data = [
"conftest.py",
"daemon_helpers.py",
"fit_scenario.py",
"lifecycle_scenario.py",
"test_properties.py",
"//feature_integration_tests/configs:lifecycle_daemon_config",
"//feature_integration_tests/test_scenarios/rust:rust_lifecycle_test_scenarios",
"@score_lifecycle_health//examples/control_application:control_daemon",
"@score_lifecycle_health//examples/control_application:lmcontrol",
"@score_lifecycle_health//examples/cpp_supervised_app",
"@score_lifecycle_health//examples/rust_supervised_app",
"@score_lifecycle_health//score/launch_manager",
],
env = {
"FIT_CPP_SUPERVISED_APP_PATH": "$(rootpath @score_lifecycle_health//examples/cpp_supervised_app)",
"FIT_LAUNCH_MANAGER_PATH": "$(rootpath @score_lifecycle_health//score/launch_manager)",
"FIT_LIFECYCLE_DAEMON_CONFIG_PATH": "$(rootpath //feature_integration_tests/configs:lifecycle_daemon_config)",
"FIT_RUST_SUPERVISED_APP_PATH": "$(rootpath @score_lifecycle_health//examples/rust_supervised_app)",
"RUST_BACKTRACE": "1",
},
env_inherit = ["FIT_ENABLE_SETCAP"],
pytest_config = "//:pyproject.toml",
# Lifecycle tests drive a shared launch_manager daemon and cannot run concurrently with each other.
tags = ["exclusive"],
deps = all_requirements,
)

test_suite(
name = "fit_rust",
tests = [
":fit_rust_lifecycle",
":fit_rust_orch",
":fit_rust_persistency",
],
)

score_py_pytest(
name = "fit_cpp_persistency",
timeout = "long",
srcs = glob(["tests/persistency/**/*.py"]),
args = [
"-m cpp",
"--traces=all",
Expand All @@ -76,6 +148,50 @@ score_py_pytest(
deps = all_requirements,
)

score_py_pytest(
name = "fit_cpp_lifecycle",
timeout = "long",
srcs = glob(["tests/lifecycle/**/*.py"]),
args = [
"-m cpp",
"--traces=all",
"--cpp-target-path=$(rootpath //feature_integration_tests/test_scenarios/cpp:cpp_test_scenarios)",
],
data = [
"conftest.py",
"daemon_helpers.py",
"fit_scenario.py",
"lifecycle_scenario.py",
"test_properties.py",
"//feature_integration_tests/configs:lifecycle_daemon_config",
"//feature_integration_tests/test_scenarios/cpp:cpp_test_scenarios",
"@score_lifecycle_health//examples/control_application:control_daemon",
"@score_lifecycle_health//examples/control_application:lmcontrol",
"@score_lifecycle_health//examples/cpp_supervised_app",
"@score_lifecycle_health//examples/rust_supervised_app",
"@score_lifecycle_health//score/launch_manager",
],
env = {
"FIT_CPP_SUPERVISED_APP_PATH": "$(rootpath @score_lifecycle_health//examples/cpp_supervised_app)",
"FIT_LAUNCH_MANAGER_PATH": "$(rootpath @score_lifecycle_health//score/launch_manager)",
"FIT_LIFECYCLE_DAEMON_CONFIG_PATH": "$(rootpath //feature_integration_tests/configs:lifecycle_daemon_config)",
"FIT_RUST_SUPERVISED_APP_PATH": "$(rootpath @score_lifecycle_health//examples/rust_supervised_app)",
},
env_inherit = ["FIT_ENABLE_SETCAP"],
pytest_config = "//:pyproject.toml",
# Lifecycle tests drive a shared launch_manager daemon and cannot run concurrently with each other.
tags = ["exclusive"],
deps = all_requirements,
)

test_suite(
name = "fit_cpp",
tests = [
":fit_cpp_lifecycle",
":fit_cpp_persistency",
],
)

test_suite(
name = "fit",
tests = [
Expand Down
Loading
Loading