Files

198 lines
5.9 KiB
Python

"""Common fixtures for the NeoPool tests."""
from collections.abc import Generator
from typing import Any
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from homeassistant.components.neopool.const import (
CONF_USE_LIGHT,
CURRENT_VERSION,
DEFAULT_PORT,
DEFAULT_UNIT_ID,
DOMAIN,
)
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT
from tests.common import MockConfigEntry
MOCK_HOST = "192.0.2.1"
MOCK_PORT = DEFAULT_PORT
MOCK_NAME = "Pool"
MOCK_SERIAL = "1234567890"
MOCK_POOL_DATA: dict[str, Any] = {
"MBF_POWER_MODULE_VERSION": 0x1234,
"MBF_PAR_VERSION": 0x100,
"MBF_PAR_MODEL": 0x0003,
"MBF_PAR_SERNUM": int(MOCK_SERIAL),
"MBF_PAR_FILTRATION_CONF": 1,
"MBF_PAR_FILT_GPIO": 1,
"MBF_PAR_LIGHTING_GPIO": 2,
"MBF_PAR_HEATING_GPIO": 3,
"MBF_PAR_PH_ACID_RELAY_GPIO": 4,
"MBF_PAR_PH_BASE_RELAY_GPIO": 5,
"MBF_PAR_RX_RELAY_GPIO": 6,
"MBF_PAR_CL_RELAY_GPIO": 7,
"MBF_PAR_CD_RELAY_GPIO": 0,
"MBF_PAR_UV_RELAY_GPIO": 1,
"MBF_PAR_FILTVALVE_GPIO": 1,
"MBF_PAR_FILTVALVE_ENABLE": 1,
"MBF_PAR_TEMPERATURE_ACTIVE": 1,
"MBF_PAR_UICFG_MACHINE": 0,
"MBF_PAR_RELAY_PH": 0,
"Hydrolysis module detected": True,
"Redox measurement module detected": True,
"pH measurement module detected": True,
"Chlorine measurement module detected": True,
"Conductivity measurement module detected": True,
"Ionization module detected": True,
"MBF_PAR_FILT_MODE": 0,
"filtration_mode": "manual",
"filtration_speed_state": "off",
"MBF_MEASURE_TEMPERATURE": 250,
"MBF_MEASURE_PH": 720,
"MBF_MEASURE_RX": 650,
"MBF_MEASURE_CL": 120,
"MBF_MEASURE_CONDUCTIVITY": 45,
"MBF_HIDRO_CURRENT": 70,
"MBF_HIDRO_VOLTAGE": 24,
"MBF_ION_CURRENT": 50,
"MBF_PAR_INTELLIGENT_INTERVALS": 4,
"MBF_PAR_INTELLIGENT_TT_NEXT_INTERVAL": 7200,
"MBF_PAR_FILTVALVE_REMAINING": 0,
"HIDRO_POLARITY": 0,
"ION_POLARITY": 0,
"PH_PUMP_STATUS": "off",
"HIDRO in Pol1": False,
"HIDRO in Pol2": False,
"HIDRO in dead time": False,
"ION in Pol1": False,
"ION in Pol2": False,
"ION in dead time": False,
"pH control module": True,
"pH pump active": False,
"pH acid pump active": False,
"Filtration Pump": False,
"MBF_PAR_HIDRO_COVER_REDUCTION": 0x0C19,
"Pool Cover": 0,
"CELL_RUNTIME_TOTAL": 0x00010000,
"CELL_RUNTIME_PART": 0x00000E10,
"CELL_RUNTIME_POLA": 0x00000708,
"CELL_RUNTIME_POLB": 0x00000708,
"CELL_RUNTIME_POL_CHANGES": 0x00000007,
}
@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.neopool.async_setup_entry", return_value=True
) as mock_setup_entry:
yield mock_setup_entry
@pytest.fixture
def mock_config_entry() -> MockConfigEntry:
"""Return a config entry with a bare-serial unique_id."""
return MockConfigEntry(
domain=DOMAIN,
title=MOCK_NAME,
unique_id=MOCK_SERIAL,
version=CURRENT_VERSION,
data={
CONF_HOST: MOCK_HOST,
CONF_PORT: MOCK_PORT,
CONF_NAME: MOCK_NAME,
"unit_id": DEFAULT_UNIT_ID,
"modbus_framer": "tcp",
},
)
@pytest.fixture
def mock_config_entry_light() -> MockConfigEntry:
"""Return a config entry with the pool light option enabled."""
return MockConfigEntry(
domain=DOMAIN,
title=MOCK_NAME,
unique_id=MOCK_SERIAL,
version=CURRENT_VERSION,
data={
CONF_HOST: MOCK_HOST,
CONF_PORT: MOCK_PORT,
CONF_NAME: MOCK_NAME,
"unit_id": DEFAULT_UNIT_ID,
"modbus_framer": "tcp",
},
options={CONF_USE_LIGHT: True},
)
@pytest.fixture
def mock_neopool_client() -> Generator[MagicMock]:
"""Patch the NeoPoolModbusClient and return a configurable mock instance."""
with (
patch(
"homeassistant.components.neopool.NeoPoolModbusClient",
autospec=True,
) as mock_client_cls,
patch(
"homeassistant.components.neopool.config_flow.async_probe_serial",
new=AsyncMock(return_value=MOCK_SERIAL),
),
):
mock_client = mock_client_cls.return_value
mock_client.async_read_all = AsyncMock(return_value=dict(MOCK_POOL_DATA))
mock_client.read_all_timers = AsyncMock(return_value={})
mock_client.async_set_relay_state = AsyncMock(return_value={})
mock_client.close = AsyncMock()
yield mock_client
@pytest.fixture
def minimal_pool_data() -> dict[str, Any]:
"""Pool data with all optional capability flags off.
Used to drive the 'should-skip' branches for supported_fn gating.
"""
return {
"MBF_POWER_MODULE_VERSION": 0x1234,
"MBF_PAR_VERSION": 0x100,
"MBF_PAR_MODEL": 0,
"MBF_PAR_SERNUM": int(MOCK_SERIAL),
"MBF_PAR_FILTRATION_CONF": 0,
"MBF_PAR_FILT_GPIO": 0,
"MBF_PAR_LIGHTING_GPIO": 0,
"MBF_PAR_HEATING_GPIO": 0,
"MBF_PAR_PH_ACID_RELAY_GPIO": 0,
"MBF_PAR_PH_BASE_RELAY_GPIO": 0,
"MBF_PAR_RX_RELAY_GPIO": 0,
"MBF_PAR_CL_RELAY_GPIO": 0,
"MBF_PAR_CD_RELAY_GPIO": 0,
"MBF_PAR_UV_RELAY_GPIO": 0,
"MBF_PAR_FILTVALVE_GPIO": 0,
"MBF_PAR_FILTVALVE_ENABLE": 0,
"MBF_PAR_TEMPERATURE_ACTIVE": 0,
"Hydrolysis module detected": False,
"Redox measurement module detected": False,
"pH measurement module detected": False,
"MBF_PAR_FILT_MODE": 0,
"filtration_mode": "manual",
"filtration_speed_state": "off",
"Filtration Pump": False,
}
@pytest.fixture
def mock_socket_connection() -> Generator[AsyncMock]:
"""Patch the lib probe in config_flow so we don't hit the network."""
with patch(
"homeassistant.components.neopool.config_flow.async_probe_serial",
new=AsyncMock(return_value=MOCK_SERIAL),
) as mock:
yield mock