Skip to content

Add test suite with mocked API, coverage CI and a pinned interpreter - #159

Open
LightD31 wants to merge 4 commits into
HarvsG:masterfrom
LightD31:pr4-tests-and-ci
Open

Add test suite with mocked API, coverage CI and a pinned interpreter#159
LightD31 wants to merge 4 commits into
HarvsG:masterfrom
LightD31:pr4-tests-and-ci

Conversation

@LightD31

Copy link
Copy Markdown

Adds the first tests to the repository (a README TODO item): 68 tests, 93% coverage of custom_components/glinet, covering the config flow (user, DHCP, reauth, reconfigure, options), entry setup/unload, the router polling and error-recovery logic, all four entity platforms, diagnostics redaction and the adjust_mac utility.

Test infrastructure

  • pytest-homeassistant-custom-component pinned to 0.13.316 — the release that pins homeassistant==2026.2.3 exactly, and the last one supporting Python 3.13. It must be bumped in lockstep with homeassistant and homeassistant-stubs
  • gli4py added to the dev dependency group (matching the manifest pin) so the integration is importable in tests; the GLinet API client is mocked at the class seam in both router.py and config_flow.py
  • Canned API responses live in tests/const.py; every mocked API method carries a __name__ because the router's error handler logs it
  • Time-driven behaviour (30s polling, consider_home aging, uptime smoothing) is tested with freezegun plus async_fire_time_changed
  • New tests.yml workflow runs pytest with coverage on pushes and PRs; mypy/pylint exclude tests/ for now

Pinned interpreter

On a fresh runner uv picked Python 3.14 (the newest allowed by requires-python), where the locked homeassistant 2026.2.3 cannot even be imported — mashumaro fails to serialize RTCIceServer. A tracked .python-version file (previously gitignored) and a requires-python cap at <3.14 keep CI on the interpreter the lockfile was resolved for. Both bounds should be raised together with the homeassistant pins above.

claude added 4 commits July 26, 2026 21:43
This repository was started from a component template and some strings
still name the components it was copied from:

- pyproject.toml describes the project as the Google Home integration
- the prettier pre-commit hook excludes custom_components/google_home/
  manifest.json, a path that does not exist here, so glinet's
  manifest.json is not actually excluded
- button.py and switch.py carry Pi-hole module and function docstrings

No behaviour changes.
GLinetRouter dispatches signal_device_new when polling finds a client it
has not seen before (router.py:368), but device_tracker.async_setup_entry
never subscribed to it: it called update_router() once at setup and then
nothing again. Devices that joined the network later got no tracker
entity until the config entry was reloaded or Home Assistant restarted.

Connect update_router to the signal, unsubscribing on unload.
…ations

Bug fixes:
- Fix sensor platform setup crash: the setup filter mutated the sensor
  list while iterating over it, and the uptime sensor raised KeyError
  when the router had not yet reported a system status (e.g. right
  after a router restart)
- Fix interface type reporting: UNKNOWN2 duplicated UNKNOWN's enum value
  making it an alias excluded from list(), so integer interface types
  >= 8 were mislabelled and type 12 raised IndexError; replaced with an
  explicit int-to-member mapping with a safe fallback
- Cancel the periodic polling timer on unload; previously every reload
  of the entry stacked another 30s polling loop
- Register the config entry update listener so options changes actually
  apply; the options flow is slimmed down to consider_home only and no
  longer echoes credentials back to the user
- Trigger the reauth flow from the polling loop; ConfigEntryAuthFailed
  raised inside a timer callback is not handled by Home Assistant
- Log in once during setup instead of three times
- Route tailscale_configured through the shared error handler so a
  timeout can no longer escape the update loop
- Validate WireGuard client configs before building state and avoid
  logging their values (they contain private key material)
- Remove duplicate wireguard_connections property, wrong @callback
  decorators on async methods and dead code

New features:
- Reauth flow: a changed router password can now be fixed from the UI
  instead of deleting and re-adding the integration
- Reconfigure flow for changing host/username/password
- Diagnostics support with credentials, MACs and SSIDs redacted

Polish:
- Entity names now use translation keys (display names unchanged)
- Sensors, switches and the reboot button report unavailable while the
  router is unreachable (device trackers keep consider_home semantics)
- Typed config entry (ConfigEntry[GLinetRouter]) and Platform enum
- consider_home is stored in entry options for new entries, with
  fallback to entry data for existing ones (no migration needed)

The manifest version is left alone so the release version stays the
maintainer's call.
Adds the first tests to the repository (a README TODO item): 68 tests
covering the config flow (user, DHCP, reauth, reconfigure, options),
entry setup/unload, the router polling and error-recovery logic, all
four entity platforms, diagnostics redaction and the adjust_mac
utility. Overall coverage of custom_components/glinet is 93%.

Test infrastructure:
- pytest-homeassistant-custom-component pinned to 0.13.316, the release
  that pins homeassistant==2026.2.3 exactly and the last one supporting
  Python 3.13; it must be bumped in lockstep with homeassistant and
  homeassistant-stubs
- gli4py added to the dev dependency group (matching the manifest pin)
  so the integration is importable in tests; the GLinet API client is
  mocked at the class seam in both router.py and config_flow.py
- Canned API responses live in tests/const.py; every mocked API method
  carries a __name__ because the router's error handler logs it
- Time-driven behavior (30s polling, consider_home aging, uptime
  smoothing) is tested with freezegun plus async_fire_time_changed
- New tests.yml workflow runs pytest with coverage reporting on pushes
  and pull requests; mypy/pylint exclude tests/ for now

The interpreter is pinned alongside: on a fresh runner uv picked Python
3.14 (the newest allowed by requires-python), where the locked
homeassistant 2026.2.3 cannot even be imported (mashumaro fails to
serialize RTCIceServer). A tracked .python-version file (previously
gitignored) and a requires-python cap at <3.14 keep CI on the
interpreter the lockfile was resolved for; both bounds should be raised
together with the homeassistant pins above.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants