Files
MeshCore/.github/workflows/run-unit-tests.yml
T
mikecarper 5d69aa461f Fix OTA retry accounting and radio delivery races
Keep catalog, manifest and leaf requests pending when the local transmit
queue rejects them instead of spending their network retry allowance.

Keep the packet selected before CAD so work becoming due during sensing
cannot bypass its own channel or pacing checks. Retire cancelled radio
retries before waiting for BUSY hardware or their retry deadline.

Wait for active transmission completion before applying firmware. Stop
admitting new transmissions after the apply drain deadline so busy queues
cannot postpone reboot indefinitely, and keep those deadlines armed across
millis rollover. Retain the existing persistence-flush backoff.

Add failing-before/fixed-after regression coverage for all four issues,
including the production OTA apply and TX guards in CI.

Validation: 1,496 native tests, 42 Python integration tests, and five
firmware builds passed across ESP32-S3, nRF52, and STM32 targets.
2026-09-15 06:45:28 -07:00

212 lines
8.1 KiB
YAML

name: Run Unit Tests
on:
push:
branches:
- main
- master
- keymindCascade
pull_request:
workflow_dispatch:
jobs:
stm32-companion-smoke:
runs-on: ubuntu-latest
steps:
- name: Clone Repo
uses: actions/checkout@v4
- name: Setup Build Environment
uses: ./.github/actions/setup-build-environment
- name: Compile ordinary STM32 USB Companion with pinned core and RadioLib
run: pio run -e RAK_3x72_companion_radio_usb
bootloader-version:
runs-on: ubuntu-latest
steps:
- name: Clone Repo
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Verify bootloader version regressions without hardware or downloads
run: python3 -B test/test_nrf52_bootloader_version.py -v
- name: Install signed-package verification dependency
run: python3 -m pip install cryptography
- name: Verify old-firmware compatibility in both OTA launchers
run: python3 -B -m unittest discover -s tools/lora_ota -p test_lora_ota_bootloader_version.py -v
- name: Verify all signed OTAFIX 2.4.6 release images
env:
MESHCORE_BOOTLOADER_MOTA_ZIP: ${{ runner.temp }}/OTAFIX-2.4.6-bootloader-mota.zip
# The test pins the archive SHA-256, verifies every .mota signature,
# and checks the exact MeshTower V2 SD CRC from the bug report.
run: |
curl --fail --location --retry 3 --max-time 120 --output "$MESHCORE_BOOTLOADER_MOTA_ZIP" \
https://github.com/mikecarper/Adafruit_nRF52_Bootloader_OTAFIX/releases/download/0.11.0-OTAFIX2.4.6/OTAFIX-2.4.6-bootloader-mota.zip
python3 -B test/test_nrf52_bootloader_version.py -v
test:
runs-on: ubuntu-latest
steps:
- name: Clone Repo
uses: actions/checkout@v4
- name: Setup Build Environment
uses: ./.github/actions/setup-build-environment
- name: Verify ArduinoJson pin
run: |
python3 -B scripts/check_arduinojson_pin.py --self-test
python3 -B scripts/check_arduinojson_pin.py
- name: Run Unit Tests
run: pio test -e native -e native_kiss_modem -vv
- name: Verify filter playground modes and built-in defaults
run: node scripts/test_filter_tool.js
- name: Verify bridge filter wiring and shorthand permissions
run: python3 -B test/test_transport_filter_wiring.py -v
- name: Verify Companion contact and channel TX routing
run: |
sudo apt-get update
sudo apt-get install -y libssl-dev
python3 -B test/test_companion_tx_routing.py -v
python3 -B test/test_contact_cache.py -v
- name: Verify receive recovery and pinned radio status transport
run: |
python3 -B test/test_radio_receive_contract.py
python3 - <<'PY'
from pathlib import Path
import re
import subprocess
dependency = re.search(r'https://github.com/jgromes/RadioLib.git#[0-9a-f]{40}',
Path('platformio.ini').read_text()).group(0)
Path('.pio/libdeps/radio-status-test').mkdir(parents=True, exist_ok=True)
subprocess.run(['pio', 'pkg', 'install', '--global', '--library', dependency,
'--storage-dir', '.pio/libdeps/radio-status-test'], check=True)
PY
python3 -B test/test_sx126x_receive_mode.py
- name: Verify temporary-radio timing and exact reply delivery
run: |
python3 -B test/test_carrier_wave.py
python3 -B test/test_radio_profile_cli.py
python3 -B test/test_radio_profile_scan.py
python3 -B test/test_repeater_radio_timing_integration.py
python3 -B test/test_temp_radio_reply_delivery_contract.py
python3 -B test/test_reply_tx_integration.py
python3 -B test/test_ota_speed.py -v
python3 -B test/test_ota_apply_delivery.py -v
- name: Verify dual-profile switching and chirp timing
working-directory: test
run: >-
python3 -B -m unittest -v
test_sx1262_profile_switch test_sx1262_batched_modulation
test_radio_chirp_math
- name: Verify radio lab collectors and compiled experiment contracts
run: |
python3 -B -m unittest discover -s test -p 'test_profile_*.py' -v
python3 -B -m unittest discover -s tools/hil -p 'test_*.py' -v
- name: Verify ESP32 static DRAM budget
run: |
python3 -B test/test_esp32_dram.py
python3 -B test/test_elrs_power.py
python3 -B test/test_ota_heap_context.py
python3 -B test/test_client_acl_spiffs.py
- name: Verify ESP32 USB sleep and G3 button wake
run: python3 -B test/test_esp32_usb_sleep.py
- name: Verify Companion ASCII defaults and USB session cleanup
run: |
python3 -B test/test_companion_usb_default.py
python3 -B test/test_nrf52_usb_client.py
python3 -B test/test_esp32_usb_serial_hygiene.py
python3 -B test/test_stm32_float_conversion.py
- name: Verify Companion contact persistence and OTA sleep guards
run: python3 -B test/test_companion_contact_sleep_contract.py -v
- name: Verify Companion Bluetooth CLI connection protection
run: python3 -B test/test_companion_bluetooth_control.py -v
- name: Verify WiFi, ESP-NOW and combined wireless controls
run: |
python3 -B test/test_wireless_control.py -v
python3 -B test/test_espnow_radio_lifecycle.py -v
- name: Verify message reader buttons, touch targets, and footer layouts
working-directory: test
run: >-
python3 -B -m unittest
test_message_navigation test_companion_john test_reader_touch_coordinates
test_touch_debug_overlay test_touch_debug_cli test_color_theme
test_indicator_messages_profile test_t096_message_footer_profile
test_indicator_display_profile test_indicator_render_profile
test_indicator_exclusive_transport test_companion_transport_selector
- name: Verify logging sleep guards and instructions
run: |
python3 -B test/test_logging_sleep_contract.py
python3 -B test/test_picker_controls_generator.py
node test/test_firmware_picker.js
- name: Verify Full logging compiler flags and packaged capabilities
run: |
python3 -B test/test_full_build_flag_dedup.py
python3 -B test/test_full_logging_compile.py
python3 -B test/test_full_logging_resume.py
python3 -B test/test_firmware_capabilities.py
bash test/test_build_profiles.sh
- name: Verify nRF52 UF2-reset CLI coverage
run: python3 -B test/test_nrf52_uf2reset_cli.py
- name: Verify CLI setting dispatch and get-set coverage
run: |
python3 -B test/test_path_hash_cli.py
python3 -B test/test_cli_settings_contract.py
python3 -B test/test_local_cli_access.py
- name: Verify firmware memory budgets and nRF52 Bluetooth startup
run: |
bash test/test_build_size_detection.sh
python3 -B test/test_firmware_ram.py
python3 -B test/test_cascade_release_package.py
python3 -B test/test_t096_full_memory.py
python3 -B test/test_nrf52_ble_startup.py
python3 -B test/test_nrf52_usb_power.py
python3 -B test/test_shared_mota_queue.py
- name: Verify Companion Bluetooth settings and WebConfig
run: |
python3 -B test/test_display_power.py
python3 -B test/test_companion_inbox.py
python3 -B test/test_heltec_r8_external_power.py
python3 -B test/test_bluetooth_mac_contract.py
python3 -B test/test_companion_settings_persistence_contract.py
python3 -B test/test_webconfig_ui.py
python3 -B test/test_webconfig_ui_runtime.py
- name: Upload Test Results
# Upload test results even if the test step failed.
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: .pio/build/native/