Files
MeshCore/.github/workflows/run-unit-tests.yml
T
mikecarper 617aacba42 Fix packet, delivery, clock and radio stability regressions
Reject truncated anonymous reply paths and advert metadata before copying,
while preserving timestamp-only empty-password logins. Limit room posting to
read-write/admin ACL roles, retain inbox frames until the requesting transport
accepts them, and lock raw LittleFS traversal against concurrent writes.

Separate ISR event generations from main-loop radio state. Confirm RX/TX IRQs,
detach concrete wrapper callbacks safely, and discard inconsistent LR2021 FIFO
snapshots before rearming. Preserve bridge RX frames through packet-pool
exhaustion and bound ESP-NOW retries and missing-callback recovery. Screen RTC
register layouts without losing DS1307 startup, and ignore poisoned future
contact timestamps during clock bootstrap.

Keep the nRF52 loop stack at 8 KiB while reducing the OTA listing call chain
from 7,832 to 6,056 static bytes. Retain all target names through lossless Full
Companion compression and the canonical size optimizer. Preserve constrained
STM32 filesystems and bind corrected ESP32 UART/OLED budgets to source size
assertions. Document the separately measured preexisting W12 package limits.

Adapted for this branch from meshcore-dev/MeshCore PRs #3521, #3340, #3362,
#2062, #3503, #3038, #3534, #3544 and #3512.

Validation: 1,829 native tests; sanitized parser, inbox, LittleFS, ACL, clock,
RTC, IRQ/FIFO and bridge fault tests; 332 additional Companion cases; real
RAK4631 Full and both repeater profiles, G2 Full/standard, V3 Full and both
constrained STM32 release recipes. Radio-family compile coverage continues
separately; W12 full/portable package guards remain enforced.
2026-10-09 19:56:08 -07:00

554 lines
25 KiB
YAML

name: Run Unit Tests
on:
push:
branches:
- main
- master
- keymindCascade
pull_request:
workflow_dispatch:
jobs:
management-reports:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install real crypto implementations for cross-language tests
run: |
python3 -m pip install platformio pycryptodome==3.23.0
mkdir -p .pio/libdeps/management-test
pio pkg install --global --library 'rweather/Crypto@0.4.0' --storage-dir .pio/libdeps/management-test
- name: Verify protocol, encryption, scheduling and MQTT decoding
run: |
python3 -B test/test_management_report.py -v
python3 -B test/test_management_cli_wrapper.py -v
node test/test_management_decoder.js
node scripts/test_telemetry_decoder.js
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
- name: Qualify Wio-E5 Mini Companion at release version length
run: >-
bash build.sh build-firmware wio-e5-mini_companion_radio_usb
--firmware-version v1.17.1.9-halo-keymind-cascade-dev
--radio-preset usa-cascade-fixed --profile cascade --require-ota
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 OTA orchestration and automatic relay policy cleanup
run: python3 -B -m unittest discover -s tools/lora_ota -p 'test_lora_ota*.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: Install signed-package verification dependency
run: python3 -m pip install cryptography
- 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 -e native_ota_channel -vv
- name: Verify parser, delivery, storage, permissions, clock and radio stability
run: |
python3 -B test/test_protocol_parser_bounds.py -v
python3 -B test/test_companion_offline_delivery.py -v
python3 -B test/test_companion_lfs_traversal.py -v
python3 -B test/test_room_post_permissions.py -v
python3 -B test/test_contact_clock_bootstrap.py -v
python3 -B test/test_rtc_discovery.py -v
python3 -B test/test_radio_interrupt_recovery.py -v
python3 -B test/test_bridge_recovery.py -v
- name: Verify signed private fleet management
run: |
python3 -B test/test_fleet_command_crypto.py -v
python3 -B test/test_companion_fleet_control.py -v
python3 -B test/test_fleet_channel_runtime.py -v
python3 -B test/test_fleet_role_wiring.py -v
python3 -B test/test_fleet_location.py -v
python3 -B test/test_fleet_radio_schedules.py -v
python3 -B test/test_fleet_clock_control.py -v
- name: Verify OTA channel persistence and published image tags
run: |
python3 -B test/test_ota_channel_persistence.py -v
python3 -B test/test_observer_ota_channel.py -v
python3 -B test/test_observer_build_channels.py -v
python3 -B scripts/verify_ota_channel.py --self-test
- name: Verify build output cleanup safety
run: python3 -B test/test_build_output_safety.py -v
- name: Verify serial mOTA response deadlines and RX fairness
run: python3 -B test/test_mota_serial_deadline.py -v
- 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
python3 -B test/test_rs232_runtime.py -v
python3 -B test/test_rs232_mqtt_runtime.py -v
python3 -B test/test_rs232_driver_lifecycle.py -v
- name: Verify saved repeat-off trace exception and relay guards
run: |
python3 -B test/test_repeater_trace_repeat.py -v
python3 -B test/test_repeater_trace_forwarding.py -v
- name: Verify telemetry schedule input and persistence rollback
run: python3 -B test/test_telemetry_tx_command.py -v
- name: Verify transactional telemetry preferences and legacy route recovery
run: python3 -B test/test_telemetry_tx_persistence.py -v
- name: Verify MQTT start results and connection-attempt accounting
run: python3 -B test/test_mqtt_transport_results.py -v
- name: Verify DNS lease restoration and bounded diagnostics
run: python3 -B test/test_network_dns.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_companion_discovery.py -v
python3 -B test/test_repeater_discovery.py -v
python3 -B test/test_companion_discovery_correlation.py -v
python3 -B test/test_pico_ble_queues.py -v
python3 -B test/test_companion_preferences_transaction.py -v
python3 -B test/test_companion_prefs_values.py -v
python3 -B test/test_companion_prefs_image.py -v
python3 -B test/test_companion_prefs_tail.py -v
python3 -B test/test_companion_radio_settings_transaction.py -v
python3 -B test/test_companion_prefs_transactions.py -v
python3 -B test/test_companion_primary_radio_persistence.py -v
python3 -B test/test_companion_response_bounds.py -v
python3 -B test/test_companion_ack_delivery.py -v
python3 -B test/test_companion_delayed_reply_delivery.py -v
python3 -B test/test_companion_hardware_serial.py -v
python3 -B test/test_companion_hardware_serial_gps.py -v
python3 -B test/test_companion_contact_lifetime.py -v
python3 -B test/test_companion_identity_cli.py -v
python3 -B test/test_companion_packet_stream.py -v
python3 -B test/test_companion_uncached_storage.py -v
python3 -B test/test_companion_ota_config.py -v
python3 -B test/test_ota_identity_policy.py -v
python3 -B test/test_companion_radio_gain_restore.py -v
python3 -B test/test_common_radio_persistence.py -v
python3 -B test/test_common_cli_save_results.py -v
python3 -B test/test_common_prefs_commit.py -v
python3 -B test/test_common_prefs_legacy_rxgain.py -v
python3 -B test/test_flood_policy_capacity.py -v
python3 -B test/test_flood_rule_layout.py -v
python3 -B test/test_mqtt_prefs_commit.py -v
python3 -B test/test_identity_and_settings_recovery.py -v
python3 -B test/test_contact_cache.py -v
- name: Verify receive recovery and pinned radio status transport
run: |
python3 -B test/test_dispatcher_startup_watchdog.py -v
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_spiffs_missing.py -v
python3 -B test/test_radio_reply_mutation.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
python3 -B test/test_ota_install_preflight.py -v
python3 -B test/test_ota_store_resume.py -v
python3 -B test/test_ota_catalog_lifetime.py -v
python3 -B test/test_ota_store_flash_nrf52_hybrid.py -v
python3 -B test/test_tower_bootloader_caps.py -v
python3 -B test/test_tower_auto_storage.py -v
python3 -B test/test_tower_auto_integration.py -v
python3 -B test/test_ota_dev_staging.py -v
python3 -B test/test_ota_dev_reboot_guard.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
python3 -B test/test_hil_esp32_self_serve_ota.py -v
python3 -B test/test_hil_esp32_usb_host_reboot.py -v
- name: Verify ESP32 static DRAM budget
run: |
python3 -B test/test_esp32_dram.py
python3 -B test/test_battery_charge_cli.py -v
python3 -B test/test_tbeam_charge_target.py -v
python3 -B test/test_elrs_power.py
python3 -B test/test_ota_heap_context.py
python3 -B test/test_ota_self_serve_policy.py -v
python3 -B test/test_ota_self_metadata_cache.py -v
python3 -B test/test_ota_nrf52_display_cache.py -v
python3 -B test/test_ota_device_deflate_encoder.py -v
python3 -B test/test_ota_device_deflate_role.py -v
python3 -B test/test_client_acl_spiffs.py
python3 -B test/test_client_acl_role.py -v
python3 -B test/test_client_acl_metadata.py -v
python3 -B test/test_client_acl_cli.py -v
python3 -B test/test_client_acl_response.py -v
python3 -B test/test_client_acl_infrastructure.py -v
python3 -B test/test_stored_client_reply_routes.py -v
- name: Setup Node for official app compatibility tests
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Cache pinned official app and browser protocol sources
uses: actions/cache@v4
with:
path: ~/.cache/meshcore-tests
key: official-clients-84bc39a950735aaffa93d912556852a4c22e235d0cc4e4d04790113207f13a68-aff42ad8ef2b332f24d644ff6a783f8272a88ff2
- name: Verify stock app radio and Access Control compatibility
run: |
node --version
python3 -B test/test_official_app_compatibility.py -v
- name: Verify ESP32 USB reboot sleep grace and G3 button wake
run: |
python3 -B test/test_usb_host_sleep_policy.py
python3 -B test/test_esp32_usb_sleep.py
python3 -B test/test_esp32_full_sleep.py
python3 -B test/test_esp32_full_power_lifecycle.py
- name: Verify official web console framing and power-saving idle sessions
run: |
python3 -B test/test_cpp_source.py -v
python3 -B test/test_official_web_console.py -v
python3 -B test/test_hil_linux_web_serial.py -v
python3 -B test/test_hil_slowfi_guard.py -v
- name: Verify official setup GUI initial time command deadline
run: python3 -B test/test_official_config_gui.py -v
- name: Verify ESP32 boot filesystem inventory and recovery safety
run: |
python3 -B test/test_esp32_boot_file_inventory.py -v
python3 -B test/test_esp32_boot_file_lifecycle.py -v
- name: Verify WiFi OTA startup and WebConfig handoff
run: |
python3 -B test/test_wifi_ota_start.py -v
python3 -B test/test_webconfig_ap_start.py -v
python3 -B test/test_esp32_wifi_scan_fix.py -v
python3 -B test/test_esp32_wifi_scan_recipes.py -v
- name: Verify browser OTA completion and immediate HTTP listener restart
run: python3 -B test/test_async_web_lifecycle.py -v
- name: Verify GPS status distinguishes user settings from receiver sleep
run: |
python3 -B test/test_gps_status.py
python3 -B test/test_gps_upstream_adaptations.py -v
python3 -B test/test_esp32_gps_discovery.py -v
python3 -B test/test_gps_sync_interval.py -v
python3 -B test/test_gps_sync_preferences.py -v
python3 -B test/test_t1000e_sensor_power.py -v
python3 -B test/test_sensor_battery_alerts.py -v
python3 -B test/test_sensor_subscriptions.py -v
python3 -B test/test_sensor_reply_bounds.py -v
- name: Verify Companion ASCII defaults and USB session cleanup
run: |
python3 -B test/test_companion_usb_default.py
python3 -B test/test_companion_usb_input.py
python3 -B test/test_companion_ota_includes.py
python3 -B test/test_companion_usb_logging_handoff.py
python3 -B test/test_companion_usb_mota_exit.py
python3 -B test/test_common_cli_logging_transaction.py
python3 -B test/test_usb_diagnostic_logging.py
python3 -B test/test_nrf52_usb_client.py
python3 -B test/test_nrf52_usb_lifecycle.py
python3 -B test/test_nrf52_usb_logging_contract.py
python3 -B test/test_esp32_usb_serial_hygiene.py
python3 -B test/test_esp32_tinyusb_nonblocking.py
python3 -B test/test_esp32_usb_session_fix.py
python3 -B test/test_hwcdc_tx_backport.py -v
python3 -B test/test_hwcdc_startup_session.py -v
python3 -B test/test_hwcdc_313_startup_session.py -v
python3 -B test/test_hwcdc_3311_startup_session.py -v
python3 -B test/test_esp32_hwcdc_recipes.py -v
python3 -B test/test_hwcdc_role_transport.py -v
python3 -B test/test_hwcdc_write_capacity.py -v
python3 -B test/test_esp32_file_buffer_fix.py -v
python3 -B test/test_companion_usb_logging_reply.py
python3 -B test/test_esp32_tinyusb_cooperative_output.py
python3 -B test/test_esp32_tinyusb_role_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
python3 -B test/test_esp32_cooperative_contacts.py -v
python3 -B test/test_esp32_contact_writer_batch.py -v
python3 -B test/test_esp32_contact_crc_batch.py -v
python3 -B test/test_esp32_contact_publication.py -v
python3 -B test/test_esp32_advert_cache.py -v
- name: Verify Companion Bluetooth CLI connection protection
run: python3 -B test/test_companion_bluetooth_control.py -v
- name: Verify Companion Bluetooth reboot persistence
run: python3 -B test/test_companion_bluetooth_persistence.py -v
- name: Verify nRF52 SoftDevice LTO and persistent BLE subscriptions
env:
MESHCORE_REQUIRE_ARM_COMPILER: '1'
MESHCORE_REQUIRE_DFU_EMULATOR: '1'
run: |
pio pkg install --global --tool 'platformio/toolchain-gccarmnoneeabi@1.140201.0'
python3 -B test/test_nrf52_svc_compat.py -v
python3 -B test/test_nrf52_ble_cccd_fix.py -v
pip install unicorn==2.1.4
python3 -B test/test_nrf52_ble_dfu_fix.py -v
- name: Verify WiFi, ESP-NOW and combined wireless controls
run: |
python3 -B test/test_wireless_control.py -v
python3 -B test/test_serial_wifi_sessions.py -v
python3 -B test/test_serial_ethernet_sessions.py -v
python3 -B test/test_companion_wifi_session.py -v
python3 -B test/test_espnow_radio_lifecycle.py -v
python3 -B test/test_wifi_ap_lr_safety.py -v
python3 -B test/test_espnow_runtime.py -v
python3 -B test/test_wifi_ota_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_reader 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 independent USB packet/debug logging, recovery, and instructions
run: |
python3 -B test/test_common_usb_debug.py
python3 -B test/test_companion_usb_logging.py
python3 -B test/test_usb_logging_watchdog.py
python3 -B test/test_usb_watchdog_event.py
python3 -B test/test_usb_logging_client_activity.py
python3 -B test/test_usb_logging_watchdog_runtime.py
python3 -B test/test_usb_logging_watchdog_roles.py
python3 -B test/test_nrf52_usb_console.py
python3 -B test/test_esp32_tinyusb_nonblocking.py
python3 -B test/test_esp32_tinyusb_role_hygiene.py
python3 -B test/test_logging_sleep_contract.py
python3 -B test/test_picker_controls_generator.py
python3 -B test/test_firmware_picker_package.py
node test/test_firmware_picker.js
- name: Verify Full logging compiler flags and packaged capabilities
run: |
python3 -B test/test_upstream_observer_recipes.py -v
python3 -B test/test_station_g3_sensor_recipes.py -v
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_xiao_canonical_logging.py -v
python3 -B test/test_firmware_build_recipe.py -v
python3 -B test/test_firmware_capabilities.py
MESHCORE_TEST_REAL_PIO_PATHS=1 python3 -B test/test_esp32_partition_migration_build_dir.py -v
bash test/test_build_profiles.sh
bash test/test_full_infrastructure_selection.sh
bash test/test_nrf52_ota_profiles.sh
bash test/test_xiao_qspi_combined.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
python3 -B test/test_remote_cli_command_identity.py -v
python3 -B test/test_replay_reset_integration.py -v
- name: Verify firmware memory budgets and nRF52 Bluetooth startup
env:
MESHCORE_REQUIRE_ARM_COMPILER: '1'
run: |
bash test/test_build_size_detection.sh
python3 -B test/test_firmware_ram.py
python3 -B test/test_recent_repeater_storage.py -v
python3 -B test/test_ota_cold_buffers.py -v
python3 -B test/test_neighbor_scope_storage.py
python3 -B test/test_ed25519_compact.py
python3 -B test/test_cascade_release_package.py
python3 -B test/test_release_publication.py
python3 -B test/test_local_release_full_selection.py
python3 -B test/test_local_release_capacity_archive.py
python3 -B test/test_t096_full_memory.py
python3 -B test/test_nrf52_ble_startup.py
python3 -B test/test_nrf52_ble_trace.py
python3 -B test/test_nrf52_ble_debug_tools.py
python3 -B test/test_nrf52_usb_power.py
python3 -B test/test_shared_mota_queue.py
- name: Verify opt-in RAK4631 combined Ethernet and OTA modes
run: |
python3 -B test/test_rak_combined_build_config.py -v
python3 -B test/test_rak_combined_ota.py -v
python3 -B test/test_rak_ethernet_transmit.py -v
python3 -B test/test_rak4631_ethernet_runtime.py -v
- name: Verify nRF52 infrastructure trims and unchanged Companion scope
run: |
python3 -B test/test_nrf52_flash_trim.py -v
python3 -B test/test_nrf52_size_profile.py -v
python3 -B test/test_nrf52_tft_font_trim.py -v
python3 -B test/test_ota_target_names.py -v
python3 -B test/test_ota_cli_listing.py -v
- name: Verify compact same-size fonts and lossless rendering
run: |
python3 -B test/test_compact_arial.py -v
python3 -B test/test_compact_noto.py -v
python3 -B test/test_nrf52_font_license.py -v
python3 -B test/test_oled_font_experiments.py -v
python3 -B test/test_font_family_trials.py -v
- name: Verify Companion Bluetooth settings and WebConfig
run: |
python3 -B test/test_gps_voice_buttons.py -v
python3 -B test/test_gps_voice_generator.py -v
python3 -B test/test_button_voice_actions.py -v
python3 -B test/test_button_voice_generator.py -v
python3 -B test/test_button_voice_preview.py -v
python3 -B test/test_g726_voice.py -v
MESH_G726_TEST_SANITIZERS=1 python3 -B test/test_g726_voice.py -v
python3 -B test/test_g726_voice_generator.py -v
python3 -B test/test_voice_prefixes.py -v
MESH_VOICE_TEST_SANITIZERS=1 python3 -B test/test_voice_prefixes.py -v
python3 -B test/test_nimble_companion.py
python3 -B test/test_bluetooth_pairing_ui.py
python3 -B test/test_companion_pairing_display.py
python3 -B test/test_companion_identity_startup.py
python3 -B test/test_startup_screen.py
node test/test_notification_builder.js
python3 -B test/test_notification_settings.py
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_gzip.py
python3 -B test/test_webconfig_secret_masking.py
python3 -B test/test_webconfig_station_ownership.py -v
python3 -B test/test_mqtt_canonical_wifi.py -v
python3 -B test/test_mqtt_ap_ownership.py -v
python3 -B test/test_companion_ap_ownership.py -v
python3 -B test/test_heltec_v4_wifi_setup_page.py -v
python3 -B test/test_sensor_webconfig_capabilities.py -v
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/
hosted-doc-links:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install the documentation renderer
run: python3 -m pip install mkdocs==1.6.1 mkdocs-material==9.7.7
- name: Verify source links and published page routes
run: python3 -B test/test_hosted_doc_links.py -v
- name: Verify hosted-link visibility and navigation
run: node test/test_hosted_doc_links.js