test(config): pin the Jellyfin name tiers and the address redaction (t41)

Two acceptance items that had no test of their own:

* the Jellyfin auto-detect tiers. t41 replaced the entity-derived search key
  (the Android TV Remote entity's friendly_name) with the names setup already
  knows — the name the user typed, then the discovery device name. Three tests
  pin it, the third being the regression: a Jellyfin player matching the *atv*
  friendly_name, with a serving state, used to be auto-detected; now only the
  typed/discovered names search. Red proof on the pre-t41 tree (60d884b):
  `_find_jellyfin_entity(hass, "jellyfin shield")` DID match
  media_player.jellyfin_shield there.

* diagnostics redaction of the renamed address field. The G14 field list already
  carried "host" (alongside the legacy spellings), but the test only exercised
  the legacy keys — so a future edit could have dropped the live one unnoticed.
  The fixture and assertion now cover both spellings.

Verified: 337 passed / 2 skipped, 338 / 1 with androidtvremote2, ruff clean.
This commit is contained in:
James Mackay committed 2026-10-11 06:26:42 +01:00
1 parent 130dee4bc6
commit aea9f9f9d2
2 files changed
+93 -1

No files matched your search

+3 -1
View File
@@ -1034,7 +1034,8 @@ class TestEntryDiagnostics:
options={ options={
"adb_command_enabled": True, "adb_command_enabled": True,
"protocol_pairing_code": "4821", "protocol_pairing_code": "4821",
"adb_host": "192.168.1.50", "host": "192.168.1.50", # t41: the one address field
"adb_host": "192.168.1.50", # legacy spellings stay redacted too
"protocol_host": "192.168.1.50", "protocol_host": "192.168.1.50",
}, },
title="Shield", title="Shield",
@@ -1052,6 +1053,7 @@ class TestEntryDiagnostics:
# old import pointed at homeassistant.util.diagnostic, which does not # old import pointed at homeassistant.util.diagnostic, which does not
# exist, so this pass silently did nothing and only the marker scan # exist, so this pass silently did nothing and only the marker scan
# (pairing-/key-shaped names) masked anything. # (pairing-/key-shaped names) masked anything.
assert payload["entry"]["options"]["host"] == "**REDACTED**"
assert payload["entry"]["options"]["adb_host"] == "**REDACTED**" assert payload["entry"]["options"]["adb_host"] == "**REDACTED**"
assert payload["entry"]["options"]["protocol_host"] == "**REDACTED**" assert payload["entry"]["options"]["protocol_host"] == "**REDACTED**"
assert payload["entry"]["data"]["nested"]["adb_host"] == "**REDACTED**" assert payload["entry"]["data"]["nested"]["adb_host"] == "**REDACTED**"
+90
View File
@@ -33,6 +33,7 @@ from nsh.const import (
CONF_ADB_ENABLED, CONF_ADB_ENABLED,
CONF_ADB_PORT, CONF_ADB_PORT,
CONF_HOST, CONF_HOST,
CONF_JELLYFIN_ENTITY,
CONF_PAIRING_CODE, CONF_PAIRING_CODE,
CONF_PROTOCOL_ENABLED, CONF_PROTOCOL_ENABLED,
CONF_SKIP_PAIRING, CONF_SKIP_PAIRING,
@@ -581,6 +582,95 @@ class TestDiscoveryPrefill:
assert defaults[CONF_HOST] == DISCOVERED_HOST assert defaults[CONF_HOST] == DISCOVERED_HOST
class TestJellyfinAutoDetect:
"""t41: auto-detect searches with the names setup already knows.
The removed tier resolved the Android TV Remote entity's ``friendly_name``
and searched the Jellyfin registry with THAT. What remains is the name the
user typed and the device name from discovery — and another integration's
entity is never consulted, not even as a search term.
"""
def _patch_registry(self, monkeypatch, entity_ids):
er = sys.modules["homeassistant.helpers.entity_registry"]
entities = {
eid: SimpleNamespace(
domain="media_player",
platform="jellyfin",
entity_id=eid,
original_name=eid.split(".", 1)[1].replace("_", " "),
disabled_by=None,
)
for eid in entity_ids
}
monkeypatch.setattr(
er, "async_get", lambda hass: SimpleNamespace(entities=entities)
)
async def test_the_typed_name_finds_the_jellyfin_player(self, tmp_path, monkeypatch):
module = _form_module()
_patch_protocol(monkeypatch, module)
self._patch_registry(monkeypatch, ["media_player.jellyfin_living_room"])
flow, hass = _new_flow(module, tmp_path)
state = SimpleNamespace(state="idle")
hass.states = SimpleNamespace(
get=lambda eid: state if eid == "media_player.jellyfin_living_room" else None
)
await flow.async_step_user(
_user_input(**{"name": "Jellyfin Living Room", CONF_PROTOCOL_ENABLED: True})
)
assert flow._user_data[CONF_JELLYFIN_ENTITY] == "media_player.jellyfin_living_room"
async def test_the_discovered_device_name_is_the_second_tier(
self, tmp_path, monkeypatch
):
module = _form_module()
_patch_protocol(monkeypatch, module)
self._patch_registry(monkeypatch, ["media_player.jellyfin_living_room"])
flow, hass = _new_flow(module, tmp_path)
state = SimpleNamespace(state="idle")
hass.states = SimpleNamespace(
get=lambda eid: state if eid == "media_player.jellyfin_living_room" else None
)
flow._discovered_name = "jellyfin living room"
await flow.async_step_user(
_user_input(**{"name": "Living Room TV", CONF_PROTOCOL_ENABLED: True})
)
assert flow._user_data[CONF_JELLYFIN_ENTITY] == "media_player.jellyfin_living_room"
async def test_another_integrations_entity_is_not_a_search_term(
self, tmp_path, monkeypatch
):
"""The regression pin: the old tier searched with the atv friendly_name.
A Jellyfin player matches THAT name, and the state machine serves it, so
the pre-t41 code auto-detected it. Only the typed name may search now.
"""
module = _form_module()
_patch_protocol(monkeypatch, module)
self._patch_registry(monkeypatch, ["media_player.jellyfin_shield"])
flow, hass = _new_flow(module, tmp_path)
atv_state = SimpleNamespace(
state="idle", attributes={"friendly_name": "jellyfin shield"}
)
state = SimpleNamespace(state="idle")
hass.states = SimpleNamespace(
get=lambda eid: state
if eid == "media_player.jellyfin_shield"
else (atv_state if eid == "media_player.shield" else None)
)
await flow.async_step_user(
_user_input(**{"name": "Living Room", CONF_PROTOCOL_ENABLED: True})
)
assert flow._user_data[CONF_JELLYFIN_ENTITY] == ""
class TestTransportsDefaultOn: class TestTransportsDefaultOn:
"""t41: the two native transports are OURS — both start enabled. """t41: the two native transports are OURS — both start enabled.