Improve Syncthru tests (#142338)

This commit is contained in:
Joost Lekkerkerker 2025-04-08 23:55:00 +02:00 committed by GitHub
parent 5d8c90ae0d
commit 528ca49368
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 232 additions and 51 deletions

View File

@ -0,0 +1,29 @@
"""Conftest for the SyncThru integration tests."""
from collections.abc import Generator
from unittest.mock import AsyncMock, patch
import pytest
from homeassistant.components.syncthru import DOMAIN
from tests.common import load_json_object_fixture
@pytest.fixture
def mock_syncthru() -> Generator[AsyncMock]:
"""Mock the SyncThru class."""
with (
patch(
"homeassistant.components.syncthru.SyncThru",
autospec=True,
) as mock_syncthru,
patch(
"homeassistant.components.syncthru.config_flow.SyncThru", new=mock_syncthru
),
):
client = mock_syncthru.return_value
client.model.return_value = "C430W"
client.is_unknown_state.return_value = False
client.raw.return_value = load_json_object_fixture("state.json", DOMAIN)
yield client

View File

@ -0,0 +1,182 @@
{
"status": {
"hrDeviceStatus": 3,
"status1": "",
"status2": "",
"status3": "",
"status4": ""
},
"identity": {
"model_name": "C430W",
"device_name": "Samsung C430W",
"host_name": "SEC84251907C415",
"location": "Living room",
"serial_num": "08HRB8GJ3F019DD",
"ip_addr": "192.168.0.251",
"ipv6_link_addr": "",
"mac_addr": "84:25:19:07:C4:15",
"admin_email": "",
"admin_name": "",
"admin_phone": "",
"customer_support": ""
},
"toner_black": {
"opt": 1,
"remaining": 8,
"cnt": 1176,
"newError": "C1-5110"
},
"toner_cyan": {
"opt": 1,
"remaining": 98,
"cnt": 25,
"newError": ""
},
"toner_magenta": {
"opt": 1,
"remaining": 98,
"cnt": 25,
"newError": ""
},
"toner_yellow": {
"opt": 1,
"remaining": 97,
"cnt": 27,
"newError": ""
},
"drum_black": {
"opt": 0,
"remaining": 44,
"newError": ""
},
"drum_cyan": {
"opt": 0,
"remaining": 100,
"newError": ""
},
"drum_magenta": {
"opt": 0,
"remaining": 100,
"newError": ""
},
"drum_yellow": {
"opt": 0,
"remaining": 100,
"newError": ""
},
"drum_color": {
"opt": 1,
"remaining": 44,
"newError": ""
},
"tray1": {
"opt": 1,
"paper_size1": 4,
"paper_size2": 0,
"paper_type1": 2,
"paper_type2": 0,
"paper_level": 0,
"capa": 150,
"newError": ""
},
"tray2": {
"opt": 0,
"paper_size1": 0,
"paper_size2": 0,
"paper_type1": 2,
"paper_type2": 0,
"paper_level": 0,
"capa": 0,
"newError": ""
},
"tray3": {
"opt": 0,
"paper_size1": 0,
"paper_size2": 0,
"paper_type1": 2,
"paper_type2": 0,
"paper_level": 0,
"capa": 0,
"newError": ""
},
"tray4": {
"opt": 0,
"paper_size1": 0,
"paper_size2": 0,
"paper_type1": 2,
"paper_type2": 0,
"paper_level": 0,
"capa": 0,
"newError": ""
},
"tray5": {
"opt": 0,
"paper_size1": 0,
"paper_size2": 0,
"paper_type1": 2,
"paper_type2": 0,
"paper_level": 0,
"capa": 0,
"newError": "0"
},
"mp": {
"opt": 0,
"paper_size1": 0,
"paper_size2": 0,
"paper_type1": 2,
"paper_type2": 0,
"paper_level": 0,
"capa": 0,
"newError": ""
},
"manual": {
"opt": 0,
"paper_size1": 0,
"paper_size2": 0,
"paper_type1": 2,
"paper_type2": 0,
"capa": 0,
"newError": ""
},
"GXI_INTRAY_MANUALFEEDING_TRAY_SUPPORT": 0,
"GXI_INSTALL_OPTION_MULTIBIN": 0,
"multibin": [0],
"outputTray": [[1, 50, ""]],
"capability": {
"hdd": {
"opt": 2,
"capa": 40
},
"ram": {
"opt": 65536,
"capa": 65536
},
"scanner": {
"opt": 0,
"capa": 0
}
},
"options": {
"hdd": 0,
"wlan": 1
},
"GXI_ACTIVE_ALERT_TOTAL": 2,
"GXI_ADMIN_WUI_HAS_DEFAULT_PASS": 0,
"GXI_SUPPORT_COLOR": 1,
"GXI_SYS_LUI_SUPPORT": 0,
"GXI_A3_SUPPORT": 0,
"GXI_TRAY2_MANDATORY_SUPPORT": 0,
"GXI_SWS_ADMIN_USE_AAA": 0,
"GXI_TONER_BLACK_VALID": 1,
"GXI_TONER_CYAN_VALID": 1,
"GXI_TONER_MAGENTA_VALID": 1,
"GXI_TONER_YELLOW_VALID": 1,
"GXI_IMAGING_BLACK_VALID": 1,
"GXI_IMAGING_CYAN_VALID": 1,
"GXI_IMAGING_MAGENTA_VALID": 1,
"GXI_IMAGING_YELLOW_VALID": 1,
"GXI_IMAGING_COLOR_VALID": 1,
"GXI_SUPPORT_PAPER_SETTING": 1,
"GXI_SUPPORT_PAPER_LEVEL": 0,
"GXI_SUPPORT_MULTI_PASS": 1
}

View File

@ -1,12 +1,10 @@
"""Tests for syncthru config flow.""" """Tests for syncthru config flow."""
import re from unittest.mock import AsyncMock, patch
from unittest.mock import patch
from pysyncthru import SyncThruAPINotSupported from pysyncthru import SyncThruAPINotSupported
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.syncthru.config_flow import SyncThru
from homeassistant.components.syncthru.const import DOMAIN from homeassistant.components.syncthru.const import DOMAIN
from homeassistant.const import CONF_NAME, CONF_URL from homeassistant.const import CONF_NAME, CONF_URL
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -21,7 +19,6 @@ from homeassistant.helpers.service_info.ssdp import (
) )
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
from tests.test_util.aiohttp import AiohttpClientMocker
FIXTURE_USER_INPUT = { FIXTURE_USER_INPUT = {
CONF_URL: "http://192.168.1.2/", CONF_URL: "http://192.168.1.2/",
@ -29,25 +26,7 @@ FIXTURE_USER_INPUT = {
} }
def mock_connection(aioclient_mock): async def test_show_setup_form(hass: HomeAssistant, mock_syncthru: AsyncMock) -> None:
"""Mock syncthru connection."""
aioclient_mock.get(
re.compile("."),
text="""
{
\tstatus: {
\thrDeviceStatus: 2,
\tstatus1: " Sleeping... "
\t},
\tidentity: {
\tserial_num: "000000000000000",
\t}
}
""",
)
async def test_show_setup_form(hass: HomeAssistant) -> None:
"""Test that the setup form is served.""" """Test that the setup form is served."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}, data=None DOMAIN, context={"source": config_entries.SOURCE_USER}, data=None
@ -58,7 +37,7 @@ async def test_show_setup_form(hass: HomeAssistant) -> None:
async def test_already_configured_by_url( async def test_already_configured_by_url(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant, mock_syncthru: AsyncMock
) -> None: ) -> None:
"""Test we match and update already configured devices by URL.""" """Test we match and update already configured devices by URL."""
@ -69,7 +48,6 @@ async def test_already_configured_by_url(
title="Already configured", title="Already configured",
unique_id=udn, unique_id=udn,
).add_to_hass(hass) ).add_to_hass(hass)
mock_connection(aioclient_mock)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
@ -83,44 +61,39 @@ async def test_already_configured_by_url(
assert result["result"].unique_id == udn assert result["result"].unique_id == udn
async def test_syncthru_not_supported(hass: HomeAssistant) -> None: async def test_syncthru_not_supported(
hass: HomeAssistant, mock_syncthru: AsyncMock
) -> None:
"""Test we show user form on unsupported device.""" """Test we show user form on unsupported device."""
with patch.object(SyncThru, "update", side_effect=SyncThruAPINotSupported): mock_syncthru.update.side_effect = SyncThruAPINotSupported
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
context={"source": config_entries.SOURCE_USER}, context={"source": config_entries.SOURCE_USER},
data=FIXTURE_USER_INPUT, data=FIXTURE_USER_INPUT,
) )
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user" assert result["step_id"] == "user"
assert result["errors"] == {CONF_URL: "syncthru_not_supported"} assert result["errors"] == {CONF_URL: "syncthru_not_supported"}
async def test_unknown_state(hass: HomeAssistant) -> None: async def test_unknown_state(hass: HomeAssistant, mock_syncthru: AsyncMock) -> None:
"""Test we show user form on unsupported device.""" """Test we show user form on unsupported device."""
with ( mock_syncthru.is_unknown_state.return_value = True
patch.object(SyncThru, "update"), result = await hass.config_entries.flow.async_init(
patch.object(SyncThru, "is_unknown_state", return_value=True), DOMAIN,
): context={"source": config_entries.SOURCE_USER},
result = await hass.config_entries.flow.async_init( data=FIXTURE_USER_INPUT,
DOMAIN, )
context={"source": config_entries.SOURCE_USER},
data=FIXTURE_USER_INPUT,
)
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user" assert result["step_id"] == "user"
assert result["errors"] == {CONF_URL: "unknown_state"} assert result["errors"] == {CONF_URL: "unknown_state"}
async def test_success( async def test_success(hass: HomeAssistant, mock_syncthru: AsyncMock) -> None:
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test successful flow provides entry creation data.""" """Test successful flow provides entry creation data."""
mock_connection(aioclient_mock)
with patch( with patch(
"homeassistant.components.syncthru.async_setup_entry", return_value=True "homeassistant.components.syncthru.async_setup_entry", return_value=True
) as mock_setup_entry: ) as mock_setup_entry:
@ -129,18 +102,15 @@ async def test_success(
context={"source": config_entries.SOURCE_USER}, context={"source": config_entries.SOURCE_USER},
data=FIXTURE_USER_INPUT, data=FIXTURE_USER_INPUT,
) )
await hass.async_block_till_done()
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["data"][CONF_URL] == FIXTURE_USER_INPUT[CONF_URL] assert result["data"][CONF_URL] == FIXTURE_USER_INPUT[CONF_URL]
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
async def test_ssdp(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker) -> None: async def test_ssdp(hass: HomeAssistant, mock_syncthru: AsyncMock) -> None:
"""Test SSDP discovery initiates config properly.""" """Test SSDP discovery initiates config properly."""
mock_connection(aioclient_mock)
url = "http://192.168.1.2/" url = "http://192.168.1.2/"
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,