1
0
mirror of https://github.com/home-assistant/core.git synced 2026-07-04 05:05:38 +01:00
Files
core/tests/components/syncthing/test_init.py
T
2026-07-02 16:50:08 +02:00

144 lines
4.1 KiB
Python

"""Tests for the syncthing integration setup and client."""
import asyncio
from unittest.mock import MagicMock, patch
from aiosyncthing.exceptions import SyncthingError
from freezegun.api import FrozenDateTimeFactory
import pytest
from homeassistant.components.syncthing.const import (
DOMAIN,
EVENTS,
RECONNECT_INTERVAL,
SERVER_AVAILABLE,
SERVER_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import dispatcher
from . import SERVER_ID
from tests.common import (
MockConfigEntry,
async_fire_time_changed,
load_json_object_fixture,
)
async def test_syncthing_client_reconnect_on_error(
hass: HomeAssistant,
entry: MockConfigEntry,
mock_syncthing_client: MagicMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test SyncthingClient reconnects when server becomes unavailable."""
call_count = 0
async def mock_listen():
"""Mock listen that raises error first, then succeeds."""
nonlocal call_count
call_count += 1
if call_count == 1:
raise SyncthingError("Connection lost")
while True:
yield await hass.async_add_executor_job(
load_json_object_fixture, "state_changed_event.json", DOMAIN
)
mock_syncthing_client.events.last_seen_id = 10
mock_syncthing_client.events.listen = mock_listen
server_unavailable_calls = []
server_available_calls = []
async def server_unavailable_handler() -> None:
"""Handle server unavailable signal."""
server_unavailable_calls.append(True)
async def server_available_handler() -> None:
"""Handle server available signal."""
server_available_calls.append(True)
dispatcher.async_dispatcher_connect(
hass,
f"{SERVER_UNAVAILABLE}-{SERVER_ID}",
server_unavailable_handler,
)
dispatcher.async_dispatcher_connect(
hass,
f"{SERVER_AVAILABLE}-{SERVER_ID}",
server_available_handler,
)
with patch(
"homeassistant.components.syncthing.aiosyncthing.Syncthing",
autospec=True,
) as mock_class:
mock_class.return_value = mock_syncthing_client
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert len(server_unavailable_calls) >= 1
assert len(server_available_calls) == 0
freezer.tick(RECONNECT_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert len(server_available_calls) >= 1
assert await hass.config_entries.async_unload(entry.entry_id)
await hass.async_block_till_done()
@pytest.mark.parametrize(
"event_fixture",
[
"folder_summary_event.json",
"state_changed_event.json",
"folder_paused_event.json",
],
)
async def test_client_dispatches_event(
hass: HomeAssistant,
entry: MockConfigEntry,
mock_syncthing_client: MagicMock,
event_fixture: str,
) -> None:
"""Test SyncthingClient dispatches the expected signal for syncthing events."""
event = await hass.async_add_executor_job(
load_json_object_fixture, event_fixture, DOMAIN
)
async def mock_listen():
yield event
await asyncio.Event().wait()
mock_syncthing_client.events.listen = mock_listen
mock_syncthing_client.events.last_seen_id = 10
folder = event["data"].get("folder") or event["data"]["id"]
signal = f"{EVENTS[event['type']]}-{SERVER_ID}-{folder}"
received = asyncio.Event()
captured: list[dict] = []
@callback
def handler(received_event: dict) -> None:
captured.append(received_event)
received.set()
dispatcher.async_dispatcher_connect(hass, signal, handler)
with patch(
"homeassistant.components.syncthing.aiosyncthing.Syncthing",
autospec=True,
) as mock_class:
mock_class.return_value = mock_syncthing_client
assert await hass.config_entries.async_setup(entry.entry_id)
async with asyncio.timeout(5):
await received.wait()
assert captured == [event]