ci: run pytest in CI; complete dev requirements; unblock socket test

The suite was never run in CI (only hassfest/HACS), and requirements-dev
listed only pytest + smartthings-local while conftest.py needs the full
Home Assistant test harness.

- requirements-dev.txt: add pytest-homeassistant-custom-component (pulls
  in home-assistant + pytest + pytest-socket) and the integration's
  runtime deps (cbor2, pyOpenSSL, cryptography) needed to import it.
- .github/workflows/validate.yml: add a Pytest job on Python 3.14
  (current Home Assistant's floor) that installs requirements-dev and
  runs the suite.
- test_config_flow.py: the UDP liveness-sweep test needs real loopback
  sockets, which the HA harness blocks by default; take the pytest-socket
  socket_enabled fixture so it runs instead of erroring.

Full suite: 249 passed.
This commit is contained in:
Marc Billow committed 2026-07-21 02:05:57 +00:00
1 parent febc8fa4a0
commit 1576d095c8
3 files changed
+35 -2

No files matched your search

+20
View File
@@ -35,3 +35,23 @@ jobs:
uses: hacs/action@main
with:
category: integration
tests:
name: Pytest
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.14"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Run tests
run: pytest tests/ -q
+10 -1
View File
@@ -1,2 +1,11 @@
pytest>=8.0
# Test harness — pulls in home-assistant, pytest, and pytest-socket at the
# matching versions. Current Home Assistant requires Python >= 3.14; pip will
# resolve the newest home-assistant your interpreter supports.
pytest-homeassistant-custom-component>=0.13.316
# Integration runtime deps, needed to import the component under test
# (also declared in custom_components/localthings/manifest.json).
smartthings-local>=0.1.0
cbor2>=5.4.6
pyOpenSSL>=23.0
cryptography>=41.0
+5 -1
View File
@@ -67,7 +67,7 @@ def test_order_candidates_prefers_known_ports() -> None:
assert _order_candidates([49153]) == [49153]
def test_find_live_ports_detects_silent_port() -> None:
def test_find_live_ports_detects_silent_port(socket_enabled) -> None:
"""The UDP liveness sweep flags a bound-but-silent port as live and drops
ports that refuse with ICMP port-unreachable.
@@ -75,6 +75,10 @@ def test_find_live_ports_detects_silent_port() -> None:
stays silent (open|filtered), like the dishwasher in issue #13 on 49153.
Two sibling ports are reserved then closed so loopback refuses datagrams
to them, standing in for the closed ports the scan should discard.
`socket_enabled` lifts pytest-socket's default block (the HA test harness
disables real sockets); this test genuinely needs loopback UDP to exercise
the ICMP-unreachable path.
"""
import socket