Files
markandClaude Fable 5 f2bf565623 Harden RelayTV integration and prepare HACS 0.4.0 (#2)
* docs: add Home Assistant 0.4.0 hardening roadmap

* fix: protect media credentials and resume state

* feat: authenticate RelayTV API operations

* fix: make targeting and media state reliable

* test: add Home Assistant integration CI

* fix: validate API credentials during setup

* release: prepare HACS 0.4.0

* fix: align pytest dependency pin

* fix: close URL sanitizer gaps and correct player state reporting

Sync the sensitive-query-key list with the RelayTV server (adds auth,
exp, jwt, X-Emby-Token, X-Jellyfin-Token), filter query credentials
from relative URLs instead of returning them verbatim, and preserve
brackets around IPv6 literal hosts.

Also report volume on RelayTV's 0-100 scale unconditionally (a raw 1
is 1%, not full volume) and give the coordinator its own
position_updated_at stamp — the base DataUpdateCoordinator has no
last_update_success_time, so media_position_updated_at silently fell
back to now() on every read and the seek bar never extrapolated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 21:08:54 -05:00

29 lines
959 B
Python

"""Tests for RelayTV config-entry setup."""
import pytest
from homeassistant.exceptions import ConfigEntryAuthFailed
from pytest_homeassistant_custom_component.common import MockConfigEntry
from custom_components.relaytv import async_setup_entry
from custom_components.relaytv.const import CONF_API_TOKEN, CONF_BASE_URL, DOMAIN
async def test_setup_rejects_invalid_write_credentials(hass, aioclient_mock) -> None:
base_url = "http://relaytv.local:8787"
entry = MockConfigEntry(
domain=DOMAIN,
title="Living Room",
data={CONF_BASE_URL: base_url, "name": "Living Room", CONF_API_TOKEN: "wrong"},
)
entry.add_to_hass(hass)
aioclient_mock.get(f"{base_url}/status", json={"state": "idle"})
aioclient_mock.post(
f"{base_url}/auth/check",
status=401,
json={"detail": "api token required"},
)
with pytest.raises(ConfigEntryAuthFailed):
await async_setup_entry(hass, entry)