Files
core/tests/components/zeroconf/test_websocket_api.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

195 lines
5.8 KiB
Python
Raw Normal View History

"""The tests for the zeroconf WebSocket API."""
import asyncio
import socket
from unittest.mock import patch
from zeroconf import (
DNSAddress,
DNSPointer,
DNSService,
DNSText,
RecordUpdate,
const,
current_time_millis,
)
from homeassistant.components.zeroconf import DOMAIN, async_get_async_instance
from homeassistant.core import HomeAssistant
from homeassistant.generated import zeroconf as zc_gen
from homeassistant.setup import async_setup_component
from tests.typing import WebSocketGenerator
async def test_subscribe_discovery(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
) -> None:
"""Test zeroconf subscribe_discovery."""
instance = await async_get_async_instance(hass)
instance.zeroconf.cache.async_add_records(
[
DNSPointer(
"_fakeservice._tcp.local.",
const._TYPE_PTR,
const._CLASS_IN,
const._DNS_OTHER_TTL,
"wrong._wrongservice._tcp.local.",
),
DNSPointer(
"_fakeservice._tcp.local.",
const._TYPE_PTR,
const._CLASS_IN,
const._DNS_OTHER_TTL,
"foo2._fakeservice._tcp.local.",
),
DNSService(
"foo2._fakeservice._tcp.local.",
const._TYPE_SRV,
const._CLASS_IN,
const._DNS_OTHER_TTL,
0,
0,
1234,
"foo2.local.",
),
DNSAddress(
"foo2.local.",
const._TYPE_A,
const._CLASS_IN,
const._DNS_HOST_TTL,
socket.inet_aton("127.0.0.1"),
),
DNSText(
"foo2.local.",
const._TYPE_TXT,
const._CLASS_IN,
const._DNS_HOST_TTL,
b"\x13md=HASS Bridge W9DN\x06pv=1.0\x14id=11:8E:DB:5B:5C:C5"
b"\x05c#=12\x04s#=1",
),
DNSPointer(
"_fakeservice._tcp.local.",
const._TYPE_PTR,
const._CLASS_IN,
const._DNS_OTHER_TTL,
"foo3._fakeservice._tcp.local.",
),
DNSService(
"foo3._fakeservice._tcp.local.",
const._TYPE_SRV,
const._CLASS_IN,
const._DNS_OTHER_TTL,
0,
0,
1234,
"foo3.local.",
),
DNSText(
"foo3.local.",
const._TYPE_TXT,
const._CLASS_IN,
const._DNS_HOST_TTL,
b"\x13md=HASS Bridge W9DN\x06pv=1.0\x14id=11:8E:DB:5B:5C:C5"
b"\x05c#=12\x04s#=1",
),
]
)
with patch.dict(
zc_gen.ZEROCONF,
{"_fakeservice._tcp.local.": []},
clear=True,
):
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.async_block_till_done()
client = await hass_ws_client()
await client.send_json(
{
"id": 1,
"type": "zeroconf/subscribe_discovery",
}
)
async with asyncio.timeout(1):
response = await client.receive_json()
assert response["success"]
async with asyncio.timeout(1):
response = await client.receive_json()
assert response["event"] == {
"add": [
{
"ip_addresses": ["127.0.0.1"],
"name": "foo2._fakeservice._tcp.local.",
"port": 1234,
"properties": {},
"type": "_fakeservice._tcp.local.",
}
]
}
# now late inject the address record
records = [
DNSAddress(
"foo3.local.",
const._TYPE_A,
const._CLASS_IN,
const._DNS_HOST_TTL,
socket.inet_aton("127.0.0.1"),
),
]
instance.zeroconf.cache.async_add_records(records)
instance.zeroconf.record_manager.async_updates(
current_time_millis(),
[RecordUpdate(record, None) for record in records],
)
# Now for the add
async with asyncio.timeout(1):
response = await client.receive_json()
assert response["event"] == {
"add": [
{
"ip_addresses": ["127.0.0.1"],
"name": "foo3._fakeservice._tcp.local.",
"port": 1234,
"properties": {},
"type": "_fakeservice._tcp.local.",
}
]
}
# Now for the update
async with asyncio.timeout(1):
response = await client.receive_json()
assert response["event"] == {
"add": [
{
"ip_addresses": ["127.0.0.1"],
"name": "foo3._fakeservice._tcp.local.",
"port": 1234,
"properties": {},
"type": "_fakeservice._tcp.local.",
}
]
}
# now move time forward and remove the record
future = current_time_millis() + (4500 * 1000)
records = instance.zeroconf.cache.async_expire(future)
record_updates = [RecordUpdate(record, record) for record in records]
instance.zeroconf.record_manager.async_updates(future, record_updates)
instance.zeroconf.record_manager.async_updates_complete(True)
removes: set[str] = set()
for _ in range(3):
async with asyncio.timeout(1):
response = await client.receive_json()
assert "remove" in response["event"]
removes.add(next(iter(response["event"]["remove"]))["name"])
assert len(removes) == 3
assert removes == {
"foo2._fakeservice._tcp.local.",
"foo3._fakeservice._tcp.local.",
"wrong._wrongservice._tcp.local.",
}