Saumya feature lifecycle cross module integration #270
Conversation
There was a problem hiding this comment.
Pull request overview
Adds lifecycle cross-module integration scaffolding across Rust/C++ scenario runners and Python FIT infrastructure, aiming to validate Launch Manager lifecycle behavior when integrated with other S-CORE modules (notably Persistency and State Manager) in daemon-supervised environments.
Changes:
- Introduces new lifecycle scenario groups for both Rust and C++ FIT scenario executables, adding lifecycle/health-monitoring client deps.
- Adds Python daemon fixture/helpers and lifecycle test utilities/configs to support running Launch Manager daemon during FITs.
- Updates Bazel test targets and documentation to reflect daemon-focused lifecycle FIT suites.
Reviewed changes
Copilot reviewed 19 out of 20 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| pyproject.toml | Switches pytest config section to tool.pytest.ini_options; adds markers for daemon/manual/slow. |
| feature_integration_tests/test_scenarios/rust/src/scenarios/mod.rs | Registers lifecycle scenario group in Rust scenario root. |
| feature_integration_tests/test_scenarios/rust/src/scenarios/lifecycle/mod.rs | Adds lifecycle scenario group definition (Rust). |
| feature_integration_tests/test_scenarios/rust/src/scenarios/lifecycle/launch_manager_support.rs | Adds lifecycle-related Rust scenarios using lifecycle client + health monitoring APIs. |
| feature_integration_tests/test_scenarios/rust/BUILD | Adds lifecycle health/client deps to Rust scenarios build. |
| feature_integration_tests/test_scenarios/cpp/src/scenarios/mod.cpp | Registers lifecycle scenario group in C++ scenario root. |
| feature_integration_tests/test_scenarios/cpp/src/scenarios/lifecycle/launch_manager_support.h | Declares lifecycle-related C++ scenario factory functions. |
| feature_integration_tests/test_scenarios/cpp/src/scenarios/lifecycle/launch_manager_support.cpp | Implements lifecycle-related C++ scenarios (incl. lifecycle client usage). |
| feature_integration_tests/test_scenarios/cpp/BUILD | Adds lifecycle client dep to C++ scenarios build. |
| feature_integration_tests/test_cases/tests/lifecycle/test_lifecycle_state_manager_if.py | Adds daemon-based architectural interface test (Launch Manager ↔ State Manager). |
| feature_integration_tests/test_cases/tests/lifecycle/test_lifecycle_persistency_recovery.py | Adds persistency recovery test scaffolding (currently no active tests). |
| feature_integration_tests/test_cases/lifecycle_scenario.py | Adds helpers/base class for lifecycle FITs and Launch Manager config generation. |
| feature_integration_tests/test_cases/daemon_helpers.py | Adds Launch Manager daemon fixture, runfiles/bazel binary resolution, and flatbuffer config handling. |
| feature_integration_tests/test_cases/conftest.py | Adds --bazel-config and switches scenario build step to direct bazel build --config=.... |
| feature_integration_tests/test_cases/configs/daemon_launch_manager_config.json | Adds daemon Launch Manager JSON config template for config generation. |
| feature_integration_tests/test_cases/configs/BUILD | Exports daemon Launch Manager config JSON as a Bazel data file. |
| feature_integration_tests/test_cases/BUILD | Adds daemon_lifecycle_configs generation and new daemon-lifecycle FIT pytest targets/suites. |
| feature_integration_tests/README.md | Documents lifecycle FIT modes and run instructions (needs target-name corrections per review comments). |
| feature_integration_tests/LIFECYCLE_TESTS_SUMMARY.md | Adds lifecycle daemon cross-module test summary (needs status alignment per review comments). |
| feature_integration_tests/itf/test_lifecycle.py | Present as an empty file in this PR. |
Comments suppressed due to low confidence (1)
feature_integration_tests/test_cases/tests/lifecycle/test_lifecycle_persistency_recovery.py:87
test_lifecycle_persistency_recovery.pycurrently contains only helper code and no collected tests (the intended test class is removed/commented). This conflicts with the PR description and also means the suite isn't actually validating the Lifecycle ↔ Persistency recovery continuity scenario.
# Removed TestLifecyclePersistencyRecoveryContinuity class - requires supervised app recovery
# configuration not available in setcap mode
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
The created documentation from the pull request is available at: docu-html |
d93b7dd to
496662a
Compare
| Architectural interface test: Launch Manager <-> State Manager | ||
| Control Interface (activate_target) | ||
|
|
||
| Verifies that external ECU logic (here represented by a direct IPC call into | ||
| the Launch Manager control interface) can: | ||
| - Query the current run-target status | ||
| - Request a run-target transition via activate_target | ||
| - Receive confirmation that the transition was performed | ||
|
|
496662a to
bc547fd
Compare
453dc7c to
acc3003
Compare
adding feature integration test cases for other requirements removing hard fail conditions updated documents adding copilot reivew fixes Fixed restart behavior on the same instance, Hardened shutdown race handling updated the statement clearing self.process after shutdown fixed pytest build environment issues fixxing the python build issues Adding test cases for cross module integration cleaning the redundant test cases test_lifecycle_persistency_recovery.py scaffolding removed and implemented test verifies continuity across supervised app crashes for persistency Updated the docstring to accurately reflect the implementation , Removed the problematic chmod operations on user's home directory Incorrect Run Targets in Docstring. Unused control_socket Variable adding copyright fixes removing double copyright header fixes known json and bl matches to use new commits fixing the module.bazel.lock mismatch lifecycle recovery preserves persistency state , make snapshot remains readable after the second probe, Unused imports removed simulates crash by terminating first process
acc3003 to
c13608e
Compare
| # Step 1: Locate the supervised process managed by the daemon. | ||
| # The fixture configures the daemon with the version-specific supervised app, | ||
| # so this must succeed. | ||
| supervised_pid = _find_supervised_process(daemon, supervised_app_name) |
There was a problem hiding this comment.
C1 — CRITICAL: the persistency writer and the killed process are different processes, so this test is meaningless. In test_persistency_recovery_with_daemon_supervision, KVS data is written by _run_persistency_probe (lines 475, 529) — an independent scenario subprocess writing to work_dir/"kvs_supervised" (line 455). The process force-killed (line 488) is the daemon-supervised {version}_supervised_app (found here at line 467), which the daemon launches with only IDENTIFIER/PROCESSIDENTIFIER/CONFIG_PATH env vars (daemon_helpers.py:699-708) — it never touches kvs_supervised. So the 'data intact after crash' checks (lines 521, 544) are trivially true: an unrelated process's already-flushed data cannot be affected by the crash. The test would pass even if recovery corrupted the supervised app's real state or did nothing at all. It verifies no recovery↔persistency interaction. Fix: have the supervised app itself own the KVS storage that is killed and recovered, and assert on its data.
| run-target switch, and log evidence is checked. | ||
| """ | ||
|
|
||
| def test_status_query_returns_current_run_target( |
There was a problem hiding this comment.
C2 — CRITICAL: this test never sends a request; it only sleeps and greps boot logs. test_status_query_returns_current_run_target does time.sleep(1.0) → is_running() → get_logs() → substring-scan. No status query and no activate_target request is ever issued. The control interface could be entirely broken (socket never opened, query endpoint missing) and the test would still pass from unrelated boot logging.
| ] | ||
|
|
||
|
|
||
| def _try_send_activate_target( |
There was a problem hiding this comment.
C3 — CRITICAL: activate_target verification is dead code. _try_send_activate_target (this function) is never called, and _ACTIVATE_TARGET_TOKENS (line 50) is never used (grep-confirmed). So the activate_target / run-target-switch path this class advertises is entirely inert — request_run_target_start / switch_run_targets / control_commands could regress with no test signal.
| ] | ||
|
|
||
| # ── Positive evidence of a status query being answered ──────────────────────── | ||
| _STATUS_QUERY_TOKENS = [ |
There was a problem hiding this comment.
C4 — CRITICAL: self-fulfilling assertion — status tokens match any normal boot log. _STATUS_QUERY_TOKENS includes generic substrings "status", "State", "Startup", plus run-target names "startup"/"running"/"fallback" (the comments even admit these are transition names, not query responses). Any daemon that logs a startup transition satisfies the assertion at line 186 regardless of whether a query was answered — effectively assert daemon logged something.
| "feat_req__lifecycle__process_failure_react", | ||
| "feat_req__lifecycle__monitor_abnormal_term", | ||
| "feat_req__persistency__store_data", | ||
| "feat_req__lifecycle__restart_on_failure", |
There was a problem hiding this comment.
C5 — CRITICAL: traceability to non-existent requirement IDs (+ semantically wrong trace). feat_req__lifecycle__restart_on_failure and feat_req__lifecycle__recovery_action (lines 301-302) do not exist in the requirements doc (verified). The valid IDs are recovery_action_support and recov_run_target_switch. The trace is also semantically wrong: the test's own docstring (lines 442-443, 486) states the recovery action is switch_run_target → fallback_run_target, not a restart — so restart_on_failure is doubly incorrect. Fix the IDs and use recov_run_target_switch.
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # ******************************************************************************* |
There was a problem hiding this comment.
L1 — LOW: itf/test_lifecycle.py contains only a license header (no test, no wiring). The branch adds only the 12-line Eclipse header — no imports, no tests. If it was meant to register the new lifecycle tests into the itf suite, that wiring is missing; otherwise remove the empty placeholder.
| from testing_utils import BazelTools | ||
|
|
||
|
|
||
| def read_launch_manager_config(config_path: Path) -> dict[str, Any]: |
There was a problem hiding this comment.
L2 — LOW: dead helpers in lifecycle_scenario.py (and root-only defaults). read_launch_manager_config, create_launch_manager_config, create_daemon_integrated_config, add_supervised_component, copy_test_app_to_daemon_workspace (lines 31, 48, 107, 191, 238) are referenced nowhere (grep-confirmed). Besides being dead, the config builders hardcode uid/gid: 0 and would fail in unprivileged CI if ever wired up.
|
|
||
| std::cout << "Testing process security configuration" << std::endl; | ||
| std::cout << "Process UID: " << uid << ", GID: " << gid << std::endl; | ||
| std::cout << "Supplementary groups: [100, 200]" << std::endl; |
There was a problem hiding this comment.
L3 — LOW: 17 print-only lifecycle scenarios are added but exercised by no test on this branch, and they diverge C++/Rust. The launch_manager_support scenarios (process_security, process_resources, process_arguments, conditional_launching, run_targets, dependency_ordering, parallel_launching, …) are compiled/registered in both languages but no Python test added on this branch invokes them. Where they would be used they are not equivalent across languages, e.g.: C++ hardcodes Supplementary groups: [100, 200] (this line) and CPU affinity: [0, 1] (.cpp:439) while Rust reads them from input (.rs:293-299,331-334); Rust builds a real HealthMonitor in dependency/parallel scenarios while C++ only prints (.rs:104-122,164-182 vs .cpp:155-170,188-234); default/'switching' strings and missing-field handling differ (.cpp:335-336,499-507,601-615 vs .rs:265-268,364-376,434-443); and LifecycleTestInput is strict in Rust but defaulted in C++ (.rs:28-32,98-100 vs .cpp:65,79). Either wire tests to these scenarios (and make the two implementations equivalent) or drop them.
| return None | ||
|
|
||
|
|
||
| def get_binary_path(target: str, version: str = "rust") -> Path: |
There was a problem hiding this comment.
L4 — LOW: get_binary_path version parameter is unused/misleading. version is declared and documented but never used (path resolution keys only on target and FIT_BAZEL_CONFIG). The per-language differentiation actually comes from the version-specific target the caller passes; the unused param invites the false assumption that the daemon binary differs per language.
| - name: Execute Feature Integration Tests | ||
| run: | | ||
| bazel test --config=linux-x86_64 //feature_integration_tests/test_cases:fit | ||
| bazel test --config=linux-x86_64 //feature_integration_tests/test_cases:fit_daemon |
There was a problem hiding this comment.
dont modify workflow fle, handle by addidng tests to existing suite
Cross-module integration tests verify that lifecycle management integrates correctly with other S-CORE modules in end-to-end scenarios: