Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,26 @@ jobs:
pip3 install poetry
poetry install
poetry run meshtastic --version

firmware:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Python 3
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install meshtastic from local
run: |
python -m pip install --upgrade pip
pip3 install poetry
poetry install --all-extras --with dev
poetry run meshtastic --version
- name: Install meshtasticd (beta) from PPA
run: |
sudo add-apt-repository -y ppa:meshtastic/beta
sudo apt-get update
sudo apt-get install -y meshtasticd
- name: Run firmware smoke tests
run: poetry run pytest -m "smokevirt or smokemesh" -v
timeout-minutes: 15
50 changes: 50 additions & 0 deletions meshtastic/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,56 @@
from meshtastic import mt_config

from ..mesh_interface import MeshInterface
from .firmware_harness import (
CHAIN_TOPOLOGY,
DEFAULT_BASE_PORT,
SimMesh,
find_meshtasticd,
is_compatible_host,
)

# Use a different base port for the single-node fixture so it doesn't
# conflict with the multi-node mesh fixture (both are session-scoped).
SINGLE_NODE_BASE_PORT = DEFAULT_BASE_PORT + 100


def _skip_firmware_if_unavailable() -> None:
"""Skip the test when meshtasticd can't run on this host."""
if not is_compatible_host():
pytest.skip("meshtasticd firmware tests require Linux")
if find_meshtasticd() is None:
pytest.skip(
"meshtasticd not found — set MESHTASTICD_BIN or install it on PATH"
)


@pytest.fixture(scope="session")
def firmware_node():
"""A single meshtasticd sim node for smokevirt tests.

Yields the SimNode instance. The node is booted with a fresh erased
config and listens on localhost at its TCP port.
"""
_skip_firmware_if_unavailable()
mesh = SimMesh(n_nodes=1, base_port=SINGLE_NODE_BASE_PORT)
mesh.start()
yield mesh.get_node(0)
mesh.stop()


@pytest.fixture(scope="function")
def firmware_mesh():
"""A 3-node chain (A-B-C) meshtasticd sim mesh for smokemesh tests.

Yields the SimMesh instance. Nodes are connected and the SIMULATOR_APP
packet bridge is running. Node DB convergence is awaited.
"""
_skip_firmware_if_unavailable()
mesh = SimMesh(n_nodes=3, topology=CHAIN_TOPOLOGY)
mesh.start()
mesh.wait_for_convergence(timeout=30)
yield mesh
mesh.stop()


@pytest.fixture
Expand Down
Loading
Loading