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

20 KiB
Raw Blame History

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
  • 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

TL;DR quick start (copy/paste)

Mock (no hardware):

python -m venv .venv; .\.venv\Scripts\Activate.ps1; pip install -r requirements.txt; pytest -m "not hardware" -v

Hardware via MUM (current default):

# 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):

# 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
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
  1. Run the mock test suite (default interface)
python.exe -m pytest -m "not hardware" -v
  1. 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:

cd /mnt/c/Users/<your-username>/ecu-tests

2. Create a virtual environment and install dependencies

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

3. Run the mock test suite (no hardware needed)

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:

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:

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

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.

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:

explorer.exe reports/report.html

Or from PowerShell/CMD:

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:

"""
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.

$env:ECU_TESTS_CONFIG = (Resolve-Path .\config\test_config.yaml)

MUM configuration (default for hardware)

Template: config/mum.example.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

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):

$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 (FrameIO + AlmTester + the four-phase test pattern) and docs/14_power_supply.md §5 (session-managed PSU lifecycle).

Usage recipes

  • Run everything (mock and any non-hardware tests):
python.exe -m pytest -v
  • Run by marker:
python.exe -m pytest -m "smoke" -v
python.exe -m pytest -m "req_001" -v
  • Run in parallel:
python.exe -m pytest -n auto -v
  • Run the plugin self-test (verifies reporting artifacts under reports/):
python -m pytest tests\plugin\test_conftest_plugin_artifacts.py -q
  • Generate separate HTML/JUnit reports for unit vs non-unit tests:
./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):

# 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:

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