ecu-tests/README.md
Hosam-Eldin Mostafa afd9da8206 docs: hardware test infrastructure, session-managed PSU, settle-then-validate
Documents the new layers introduced over the past several commits.

- docs/19_frame_io_and_alm_helpers.md (new): full reference for the
  FrameIO and AlmTester helpers — three access levels (high/mid/low),
  full API tables, fixture wiring, cookbook patterns, and §7
  describing the four-phase SETUP/PROCEDURE/ASSERT/TEARDOWN test
  pattern with the three template flavors plus a §7.4 link to the
  PSU+LIN template.

- docs/14_power_supply.md: rewritten and expanded.
    §3 cross-platform port resolution (Windows / WSL1 / WSL2 +
       usbipd-win / Linux native compatibility table)
    §4 auto-detection via idn_substr
    §5 session-managed power: contract for tests, must-not list,
       what changed in the existing tests
    §6 the settle-then-validate pattern: two-delays table (PSU
       bench-dependent vs ECU firmware-dependent), copy-paste
       example, tuning guidance for ECU_VALIDATION_TIME_S
    §6 PSU settling characterization (-m psu_settling)
    §7 library API reference table + safe_off_on_close
    §9 troubleshooting expanded with WSL2 usbipd-win + dialout

- docs/18_test_catalog.md: voltage-tolerance section refreshed for
  the settle-then-validate shape, new "Hardware – PSU settling
  (opt-in)" category, new §8 "Hardware-test infrastructure"
  documenting conftest.py, frame_io.py, alm_helpers.py,
  psu_helpers.py, and both templates.

- docs/05_architecture_overview.md: components list split into
  framework core / hardware test layer / artifacts. Mermaid diagram
  gained a Hardware-test helpers subgraph showing FrameIO,
  AlmTester, rgb_to_pwm, and the templates. Data/control flow
  summary describes the session-managed PSU and the helper layer.

- docs/15_report_properties_cheatsheet.md: PSU section split into
  per-test (function-scoped rp) and module-scoped (testsuite
  property) blocks; added psu_resolved_port, psu_resolved_idn,
  psu_settled_s, validation_time_s.

- docs/README.md: links to the new doc 19.

- README.md, TESTING_FRAMEWORK_GUIDE.md: project-structure trees
  expanded to show the full current layout — every file and
  directory under tests/hardware/ (conftest, helpers, templates,
  tests), tests/unit/, config/, docs/, scripts/, and vendor/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 19:02:42 +02:00

500 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ECU Tests Framework
Python-based ECU testing framework built on pytest, with a pluggable LIN communication layer (Mock and MUM, with the deprecated BabyLIN adapter retained for backward compatibility), configuration via YAML, and enhanced HTML/XML reporting with rich test metadata.
> **Heads-up:** the BabyLIN adapter is **deprecated**. New tests and deployments should target MUM. BabyLIN is documented below only so existing setups can keep running while they migrate.
## Highlights
- **MUM (Melexis Universal Master) adapter** — current default for hardware tests; networked LIN master with built-in power control
- Mock LIN adapter for fast, hardware-free development
- BabyLIN adapter (DEPRECATED) using the vendor SDK's Python wrapper
- Hex flashing scaffold you can wire to UDS
- Rich pytest fixtures and example tests
- Self-contained HTML report with Title, Requirements, Steps, and Expected Results extracted from test docstrings
- JUnit XML report for CI/CD
## Quick links
- Using the framework (common runs, markers, CI, Pi): `docs/12_using_the_framework.md`
- Plugin overview (reporting, hooks, artifacts): `docs/11_conftest_plugin_overview.md`
- Power supply (Owon) usage and troubleshooting: `docs/14_power_supply.md`
- Report properties cheatsheet (standard keys): `docs/15_report_properties_cheatsheet.md`
- MUM source scripts (vendor reference): [vendor/automated_lin_test/README.md](vendor/automated_lin_test/README.md)
## TL;DR quick start (copy/paste)
Mock (no hardware):
```powershell
python -m venv .venv; .\.venv\Scripts\Activate.ps1; pip install -r requirements.txt; pytest -m "not hardware" -v
```
Hardware via MUM (current default):
```powershell
# 1. Install Melexis 'pylin' and 'pymumclient' (see vendor/automated_lin_test/install_packages.sh)
# 2. Make sure the MUM is reachable (default IP 192.168.7.2)
$env:ECU_TESTS_CONFIG = ".\config\mum.example.yaml"; pytest -m "hardware and mum" -v
```
Hardware via BabyLIN (DEPRECATED — kept for existing rigs only):
```powershell
# Place BabyLIN_library.py and native libs under .\vendor per vendor/README.md first
$env:ECU_TESTS_CONFIG = ".\config\babylin.example.yaml"; pytest -m "hardware and babylin" -v
```
## Quick start (Windows PowerShell)
1) Create a virtual environment and install dependencies
```powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
```
2) Run the mock test suite (default interface)
```powershell
python.exe -m pytest -m "not hardware" -v
```
3) View the reports
- HTML: `reports/report.html`
- JUnit XML: `reports/junit.xml`
Tip: You can change output via `--html` and `--junitxml` CLI options.
## Quick start (WSL on Windows)
Use this approach when running from **Windows Subsystem for Linux** instead of PowerShell.
### 1. Open a WSL terminal and navigate to the project
Clone or access the repo from within WSL. If the project lives on the Windows filesystem (e.g. `C:\Users\you\ecu-tests`), it is available at:
```bash
cd /mnt/c/Users/<your-username>/ecu-tests
```
### 2. Create a virtual environment and install dependencies
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
### 3. Run the mock test suite (no hardware needed)
```bash
python -m pytest -m "not hardware" -v
```
### 4. Install Melexis packages into the venv (required for hardware tests)
`pylin`, `pymumclient`, and `pylinframe` are not on PyPI — they ship with the Melexis IDE.
On Windows they live at:
```
C:\Program Files\Melexis\Melexis IDE\plugins\com.melexis.mlxide.python_1.2.0.202408130945\python\Lib\site-packages
```
which WSL exposes at `/mnt/c/Program Files/Melexis/Melexis IDE/...`.
**With your venv already activated**, copy the packages directly into it:
```bash
source .venv/bin/activate # skip if already active
MELEXIS_SITE="/mnt/c/Program Files/Melexis/Melexis IDE/plugins/com.melexis.mlxide.python_1.2.0.202408130945/python/Lib/site-packages"
VENV_SITE=$(python -c "import site; print(site.getsitepackages()[0])")
cp -r "$MELEXIS_SITE/pylin" "$VENV_SITE/"
cp -r "$MELEXIS_SITE/pymumclient" "$VENV_SITE/"
cp -r "$MELEXIS_SITE/pylinframe" "$VENV_SITE/"
```
Verify the installation:
```bash
python -c "import pylin; import pymumclient; print('OK')"
```
> **Alternative:** You can also run `bash vendor/automated_lin_test/install_packages.sh` after updating the `MELEXIS_SITE_PACKAGES` path in that script — but the commands above are simpler and target the venv directly.
### 5. Run hardware tests via MUM
```bash
export ECU_TESTS_CONFIG=./config/mum.example.yaml
python -m pytest -m "hardware and mum" -v
```
### 6. Run hardware tests via BabyLIN (DEPRECATED)
> **Deprecated.** The BabyLIN adapter is kept for backward compatibility only; new work should target MUM (step 5). The BabyLIN SDK also ships Windows-only native libraries (`.dll`), so these tests cannot run under WSL unless you have a Linux-compatible `.so` build of the SDK.
```bash
export ECU_TESTS_CONFIG=./config/babylin.example.yaml
python -m pytest -m "hardware and babylin" -v
```
### 7. View reports
Open the HTML report directly in Windows from the WSL terminal:
```bash
explorer.exe reports/report.html
```
Or from PowerShell/CMD:
```powershell
start .\reports\report.html
```
---
## Reporting: Metadata in HTML
We extract these fields from each tests docstring and render them in the HTML report:
- Title
- Description
- Requirements (e.g., REQ-001)
- Test Steps
- Expected Result
Markers like `smoke`, `hardware`, and `req_00x` are also displayed.
Example docstring format used by the plugin:
```python
"""
Title: Mock LIN Interface - Send/Receive Echo Test
Description: Validates basic send/receive functionality using the mock LIN interface with echo behavior.
Requirements: REQ-001, REQ-003
Test Steps:
1. Connect to mock interface
2. Send frame ID 0x01 with data [0x55]
3. Receive the echo within 100ms
4. Assert ID and data integrity
Expected Result:
- Echoed frame matches sent frame
"""
```
## Configuration
Default config is `config/test_config.yaml`. Override via the `ECU_TESTS_CONFIG` environment variable.
```powershell
$env:ECU_TESTS_CONFIG = (Resolve-Path .\config\test_config.yaml)
```
### MUM configuration (default for hardware)
Template: `config/mum.example.yaml`
```yaml
interface:
type: mum
host: 192.168.7.2 # MUM IP (USB-RNDIS default)
lin_device: lin0 # MUM LIN device name
power_device: power_out0 # MUM power-control device (built-in PSU)
bitrate: 19200 # LIN baudrate
boot_settle_seconds: 0.5 # Wait after power-up before sending the first frame
frame_lengths:
0x0A: 8 # ALM_Req_A
0x11: 4 # ALM_Status
```
The MUM has its own power output, so `power_supply.enabled: false` is the
typical setting when using MUM. The Owon PSU support remains for over/under-
voltage scenarios but is independent of the LIN interface.
### BabyLIN configuration (DEPRECATED)
> Retained for backward compatibility. Prefer the MUM configuration above.
Template: `config/babylin.example.yaml`
```yaml
interface:
type: babylin # deprecated; prefer "mum" or "mock"
channel: 0 # Channel index used by the SDK wrapper
bitrate: 19200 # Usually determined by SDF
sdf_path: ./vendor/Example.sdf
schedule_nr: 0 # Start this schedule on connect (-1 to skip)
```
### LIN adapter capabilities
| Adapter | Power control | Diagnostic frames (Classic checksum) | Passive listen |
| --- | --- | --- | --- |
| `mock` | n/a | n/a | yes (queue-based) |
| `mum` | yes (`power_out0`) | yes (`MumLinInterface.send_raw()``ld_put_raw`) | no — `receive(id)` triggers a slave read |
| `babylin` (deprecated) | external (Owon PSU) | via SDF / `BLC_sendCommand` | yes (frame queue) |
Switch to hardware profile and run only hardware tests (MUM example):
```powershell
$env:ECU_TESTS_CONFIG = (Resolve-Path .\config\mum.example.yaml)
python.exe -m pytest -m hardware -v
```
## Project structure
```
ecu_tests/
├── ecu_framework/ # Core framework package
│ ├── config.py # YAML config loader → typed dataclasses
│ ├── lin/
│ │ ├── base.py # LinInterface + LinFrame contract
│ │ ├── mock.py # Mock LIN adapter (no hardware)
│ │ ├── mum.py # MUM adapter (current default; Melexis pylin/pymumclient)
│ │ ├── ldf.py # LdfDatabase wrapper around ldfparser
│ │ └── babylin.py # DEPRECATED BabyLIN SDK-wrapper adapter
│ ├── power/
│ │ └── owon_psu.py # Owon PSU SCPI controller + cross-platform port resolver
│ └── flashing/
│ └── hex_flasher.py # Hex flashing scaffold
├── tests/
│ ├── conftest.py # Project-wide fixtures: config, lin, ldf, flash_ecu, rp
│ │
│ ├── unit/ # Pure-logic tests (no hardware)
│ │ ├── test_config_loader.py
│ │ ├── test_linframe.py
│ │ ├── test_ldf_database.py
│ │ ├── test_hex_flasher.py
│ │ ├── test_mum_adapter_mocked.py
│ │ └── test_babylin_adapter_mocked.py # deprecated path
│ │
│ ├── plugin/
│ │ └── test_conftest_plugin_artifacts.py # reporting plugin self-test
│ │
│ ├── hardware/ # Real-bench tests (MUM / PSU / ECU)
│ │ ├── conftest.py # Session-scoped autouse PSU fixture (powers the ECU)
│ │ ├── frame_io.py # FrameIO — generic LDF-driven send/receive/pack/unpack
│ │ ├── alm_helpers.py # AlmTester — ALM_Node domain helpers + constants
│ │ ├── psu_helpers.py # apply_voltage_and_settle — measure-rail-then-validate
│ │ ├── _test_case_template.py # ALM-only test starting point (not collected)
│ │ ├── _test_case_template_psu_lin.py # PSU + LIN test starting point (not collected)
│ │ ├── test_mum_alm_animation.py # ALM mode/update/LID checks via MUM
│ │ ├── test_mum_auto_addressing.py # BSM auto-addressing (NAD)
│ │ ├── test_e2e_mum_led_activate.py # MUM end-to-end power+activate
│ │ ├── test_overvolt.py # Voltage-tolerance (over/under/sweep)
│ │ ├── test_psu_voltage_settling.py # PSU settling-time characterization (-m psu_settling)
│ │ ├── test_owon_psu.py # PSU IDN + measurements (read-only)
│ │ └── test_e2e_power_on_lin_smoke.py # DEPRECATED BabyLIN E2E
│ │
│ ├── test_smoke_mock.py # Mock interface smoke + boundary
│ ├── test_babylin_hardware_smoke.py # DEPRECATED BabyLIN hardware
│ ├── test_babylin_hardware_schedule_smoke.py # DEPRECATED BabyLIN schedule flow
│ ├── test_babylin_wrapper_mock.py # DEPRECATED BabyLIN adapter w/ mock wrapper
│ └── test_hardware_placeholder.py
├── config/
│ ├── test_config.yaml # Default config (MUM by default)
│ ├── mum.example.yaml # MUM hardware profile
│ ├── owon_psu.example.yaml # PSU profile (copy to owon_psu.yaml)
│ ├── owon_psu.yaml # Optional per-machine PSU override
│ ├── examples.yaml # Combined mock/babylin profiles
│ └── babylin.example.yaml # DEPRECATED BabyLIN profile
├── docs/
│ ├── README.md # Documentation index
│ ├── 01_run_sequence.md # End-to-end run sequence
│ ├── 02_configuration_resolution.md
│ ├── 03_reporting_and_metadata.md
│ ├── 04_lin_interface_call_flow.md
│ ├── 05_architecture_overview.md
│ ├── 06_requirement_traceability.md
│ ├── 07_flash_sequence.md
│ ├── 08_babylin_internals.md # DEPRECATED
│ ├── 09_raspberry_pi_deployment.md
│ ├── 10_build_custom_image.md
│ ├── 11_conftest_plugin_overview.md
│ ├── 12_using_the_framework.md
│ ├── 13_unit_testing_guide.md
│ ├── 14_power_supply.md # PSU controller, resolver, session-managed power
│ ├── 15_report_properties_cheatsheet.md
│ ├── 16_mum_internals.md
│ ├── 17_ldf_parser.md
│ ├── 18_test_catalog.md
│ ├── 19_frame_io_and_alm_helpers.md # Hardware test helpers + four-phase pattern
│ └── DEVELOPER_COMMIT_GUIDE.md
├── vendor/ # Third-party + project assets
│ ├── 4SEVEN_color_lib_test.ldf # LDF used by the LIN tests
│ ├── 4SEVEN_color_lib_test.sdf # SDF for the deprecated BabyLIN path
│ ├── rgb_to_pwm.py # RGB → PWM calculator (used by ALM PWM assertions)
│ ├── led_platform.py # Platform-specific LED helpers
│ ├── Owon/
│ │ └── owon_psu_quick_demo.py # Standalone PSU demo
│ ├── automated_lin_test/ # Reference scripts (test_animation.py etc.)
│ │ ├── README.md
│ │ ├── install_packages.sh # Installs Melexis pylin/pymumclient into the venv
│ │ └── (test_*.py reference scripts)
│ ├── BabyLIN_library.py # DEPRECATED official BabyLIN SDK Python wrapper
│ ├── BLCInterfaceExample.py # DEPRECATED vendor example
│ └── BabyLIN library/ # DEPRECATED platform binaries (DLL/.so)
├── reports/ # Generated per-run (HTML, JUnit, summary, coverage)
│ ├── report.html
│ ├── junit.xml
│ ├── summary.md
│ └── requirements_coverage.json
├── scripts/
│ ├── pi_install.sh # Raspberry Pi installer
│ ├── ecu-tests.service # systemd unit
│ ├── ecu-tests.timer # systemd timer
│ ├── run_tests.sh # Convenience runner
│ ├── run_two_reports.ps1 # Split unit/non-unit report runs (Windows)
│ └── 99-babylin.rules # DEPRECATED udev rule
├── conftest_plugin.py # HTML metadata extraction + report customization
├── pytest.ini # Markers, addopts, junit_family=legacy
├── requirements.txt
├── README.md # ← you are here
└── TESTING_FRAMEWORK_GUIDE.md # Deep dive companion to this README
```
For the hardware-test layer specifically, see
[`docs/19_frame_io_and_alm_helpers.md`](docs/19_frame_io_and_alm_helpers.md)
(FrameIO + AlmTester + the four-phase test pattern) and
[`docs/14_power_supply.md`](docs/14_power_supply.md) §5
(session-managed PSU lifecycle).
## Usage recipes
- Run everything (mock and any non-hardware tests):
```powershell
python.exe -m pytest -v
```
- Run by marker:
```powershell
python.exe -m pytest -m "smoke" -v
python.exe -m pytest -m "req_001" -v
```
- Run in parallel:
```powershell
python.exe -m pytest -n auto -v
```
- Run the plugin self-test (verifies reporting artifacts under `reports/`):
```powershell
python -m pytest tests\plugin\test_conftest_plugin_artifacts.py -q
```
- Generate separate HTML/JUnit reports for unit vs non-unit tests:
```powershell
./scripts/run_two_reports.ps1
```
## BabyLIN adapter notes (DEPRECATED)
> Kept for backward compatibility. New work should target the MUM adapter.
The `ecu_framework/lin/babylin.py` implementation uses the official `BabyLIN_library.py` wrapper from the SDK. Put `BabyLIN_library.py` under `vendor/` (or on `PYTHONPATH`) along with the SDK's platform-specific libraries. Configure `sdf_path` and `schedule_nr` to load an SDF and start a schedule during connect. The adapter sends frames via `BLC_mon_set_xmit` and receives via `BLC_getNextFrameTimeout`. Instantiating `BabyLinInterface` emits a `DeprecationWarning`.
## Docs and references
- Guide: `TESTING_FRAMEWORK_GUIDE.md` (deep dive with examples and step-by-step flows)
- Reports: `reports/report.html` and `reports/junit.xml` (generated on each run)
- CI summary: `reports/summary.md` (machine-friendly run summary)
- Requirements coverage: `reports/requirements_coverage.json` (requirement → tests mapping)
- Tip: Open the HTML report on Windows with: `start .\reports\report.html`
- Configs: `config/test_config.yaml`, `config/mum.example.yaml`, `config/babylin.example.yaml` (deprecated) — copy and modify for your environment
- BabyLIN SDK placement and notes: `vendor/README.md` (deprecated; only relevant for legacy BabyLIN rigs)
- Docs index: `docs/README.md` (run sequence, config resolution, reporting, call flows)
- Raspberry Pi deployment: `docs/09_raspberry_pi_deployment.md`
- Build custom Pi image: `docs/10_build_custom_image.md`
- Pi scripts: `scripts/pi_install.sh`, `scripts/ecu-tests.service`, `scripts/ecu-tests.timer`, `scripts/run_tests.sh`
## Troubleshooting
- HTML report missing columns: ensure `pytest.ini` includes `-p conftest_plugin` in `addopts`.
- ImportError for BabyLIN_library (DEPRECATED path): verify `vendor/BabyLIN_library.py` placement and that required native libraries (DLL/.so) from the SDK are available on PATH/LD_LIBRARY_PATH. Consider migrating to the MUM adapter, which avoids vendor DLLs entirely.
- Permission errors in PowerShell: run the venv's full Python path or adjust ExecutionPolicy for scripts.
- Import errors: activate the venv and reinstall `requirements.txt`.
## Owon Power Supply (SCPI) — library, config, tests, and quick demo
We provide a reusable pyserial-based library, a hardware test integrated with the central config,
and a minimal quick demo script.
- Library: `ecu_framework/power/owon_psu.py` (class `OwonPSU`, `SerialParams`, `scan_ports`)
- Central config: `config/test_config.yaml` (`power_supply` section)
- Optionally merge `config/owon_psu.yaml` or set `OWON_PSU_CONFIG` to a YAML path
- Hardware test: `tests/hardware/test_owon_psu.py` (skips unless `power_supply.enabled` is true)
- quick demo: `vendor/Owon/owon_psu_quick_demo.py` (reads `OWON_PSU_CONFIG` or `config/owon_psu.yaml`)
Quick setup (Windows PowerShell):
```powershell
# Ensure dependencies
pip install -r .\requirements.txt
# Option A: configure centrally in test_config.yaml
# Edit config\test_config.yaml and set:
# power_supply.enabled: true
# power_supply.port: COM4
# Option B: use a separate machine-specific YAML
copy .\config\owon_psu.example.yaml .\config\owon_psu.yaml
# edit COM port and options in .\config\owon_psu.yaml
# Run the hardware PSU test (skips if disabled or missing port)
pytest -k test_owon_psu_idn_and_optional_set -m hardware -q
# Run the quick demo script
python .\vendor\Owon\owon_psu_quick_demo.py
```
YAML keys supported by `power_supply`:
```yaml
power_supply:
enabled: true
port: COM4 # or /dev/ttyUSB0
baudrate: 115200
timeout: 1.0
eol: "\n" # or "\r\n"
parity: N # N|E|O
stopbits: 1 # 1|2
xonxoff: false
rtscts: false
dsrdtr: false
idn_substr: OWON
do_set: false
set_voltage: 5.0
set_current: 0.1
```
Troubleshooting:
- If `*IDN?` is empty, confirm port, parity/stopbits, and `eol` (try `\r\n`).
- On Windows, if COM>9, use `\\.\COM10` style in some tools; here plain `COM10` usually works.
- Ensure only one program opens the COM port at a time.
## Next steps
- Replace `HexFlasher` with a production flashing routine (UDS)
- Expand tests for end-to-end ECU workflows and requirement coverage