mirror of
https://github.com/home-assistant/core.git
synced 2026-03-03 16:20:40 +00:00
* allow for different systems * installation is a load_json_*fixture param * allow installation to be parameterized * test setup of various systems * add more fixtures * test setup of integration * tweak test * tweak const * add expected state/services * extend setup test * tidy up * tidy up tweaks * code tweaks * refactor expected results dicts * woops * refatcor serialize * refactor test * tweak * tweak code * rename symbol * ensure actual I/O remains blocked * tweak * typo * use constants * Update conftest.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * change filename * add config fixture * config is a fixture * config is a fixture now 2 * lint * lint * refactor * lint * lint * restore email addr * use const * use snapshots instead of helper class * doctweak * correct snapshot --------- Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
152 lines
5.5 KiB
Python
152 lines
5.5 KiB
Python
"""Fixtures and helpers for the evohome tests."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
from datetime import datetime, timedelta
|
|
from http import HTTPMethod
|
|
from typing import Any
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from aiohttp import ClientSession
|
|
from evohomeasync2 import EvohomeClient
|
|
from evohomeasync2.broker import Broker
|
|
import pytest
|
|
|
|
from homeassistant.components.evohome import CONF_PASSWORD, CONF_USERNAME, DOMAIN
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.setup import async_setup_component
|
|
from homeassistant.util.json import JsonArrayType, JsonObjectType
|
|
|
|
from .const import ACCESS_TOKEN, REFRESH_TOKEN, USERNAME
|
|
|
|
from tests.common import load_json_array_fixture, load_json_object_fixture
|
|
|
|
|
|
def user_account_config_fixture(install: str) -> JsonObjectType:
|
|
"""Load JSON for the config of a user's account."""
|
|
try:
|
|
return load_json_object_fixture(f"{install}/user_account.json", DOMAIN)
|
|
except FileNotFoundError:
|
|
return load_json_object_fixture("default/user_account.json", DOMAIN)
|
|
|
|
|
|
def user_locations_config_fixture(install: str) -> JsonArrayType:
|
|
"""Load JSON for the config of a user's installation (a list of locations)."""
|
|
return load_json_array_fixture(f"{install}/user_locations.json", DOMAIN)
|
|
|
|
|
|
def location_status_fixture(install: str, loc_id: str | None = None) -> JsonObjectType:
|
|
"""Load JSON for the status of a specific location."""
|
|
if loc_id is None:
|
|
_install = load_json_array_fixture(f"{install}/user_locations.json", DOMAIN)
|
|
loc_id = _install[0]["locationInfo"]["locationId"] # type: ignore[assignment, call-overload, index]
|
|
return load_json_object_fixture(f"{install}/status_{loc_id}.json", DOMAIN)
|
|
|
|
|
|
def dhw_schedule_fixture(install: str) -> JsonObjectType:
|
|
"""Load JSON for the schedule of a domesticHotWater zone."""
|
|
try:
|
|
return load_json_object_fixture(f"{install}/schedule_dhw.json", DOMAIN)
|
|
except FileNotFoundError:
|
|
return load_json_object_fixture("default/schedule_dhw.json", DOMAIN)
|
|
|
|
|
|
def zone_schedule_fixture(install: str) -> JsonObjectType:
|
|
"""Load JSON for the schedule of a temperatureZone zone."""
|
|
try:
|
|
return load_json_object_fixture(f"{install}/schedule_zone.json", DOMAIN)
|
|
except FileNotFoundError:
|
|
return load_json_object_fixture("default/schedule_zone.json", DOMAIN)
|
|
|
|
|
|
def mock_get_factory(install: str) -> Callable:
|
|
"""Return a get method for a specified installation."""
|
|
|
|
async def mock_get(
|
|
self: Broker, url: str, **kwargs: Any
|
|
) -> JsonArrayType | JsonObjectType:
|
|
"""Return the JSON for a HTTP get of a given URL."""
|
|
|
|
# a proxy for the behaviour of the real web API
|
|
if self.refresh_token is None:
|
|
self.refresh_token = f"new_{REFRESH_TOKEN}"
|
|
|
|
if (
|
|
self.access_token_expires is None
|
|
or self.access_token_expires < datetime.now()
|
|
):
|
|
self.access_token = f"new_{ACCESS_TOKEN}"
|
|
self.access_token_expires = datetime.now() + timedelta(minutes=30)
|
|
|
|
# assume a valid GET, and return the JSON for that web API
|
|
if url == "userAccount": # userAccount
|
|
return user_account_config_fixture(install)
|
|
|
|
if url.startswith("location"):
|
|
if "installationInfo" in url: # location/installationInfo?userId={id}
|
|
return user_locations_config_fixture(install)
|
|
if "location" in url: # location/{id}/status
|
|
return location_status_fixture(install)
|
|
|
|
elif "schedule" in url:
|
|
if url.startswith("domesticHotWater"): # domesticHotWater/{id}/schedule
|
|
return dhw_schedule_fixture(install)
|
|
if url.startswith("temperatureZone"): # temperatureZone/{id}/schedule
|
|
return zone_schedule_fixture(install)
|
|
|
|
pytest.fail(f"Unexpected request: {HTTPMethod.GET} {url}")
|
|
|
|
return mock_get
|
|
|
|
|
|
async def block_request(
|
|
self: Broker, method: HTTPMethod, url: str, **kwargs: Any
|
|
) -> None:
|
|
"""Fail if the code attempts any actual I/O via aiohttp."""
|
|
|
|
pytest.fail(f"Unexpected request: {method} {url}")
|
|
|
|
|
|
@pytest.fixture
|
|
def evo_config() -> dict[str, str]:
|
|
"Return a default/minimal configuration."
|
|
return {
|
|
CONF_USERNAME: USERNAME,
|
|
CONF_PASSWORD: "password",
|
|
}
|
|
|
|
|
|
@patch("evohomeasync.broker.Broker._make_request", block_request)
|
|
@patch("evohomeasync2.broker.Broker._client", block_request)
|
|
async def setup_evohome(
|
|
hass: HomeAssistant,
|
|
test_config: dict[str, str],
|
|
install: str = "default",
|
|
) -> MagicMock:
|
|
"""Set up the evohome integration and return its client.
|
|
|
|
The class is mocked here to check the client was instantiated with the correct args.
|
|
"""
|
|
|
|
with (
|
|
patch("homeassistant.components.evohome.evo.EvohomeClient") as mock_client,
|
|
patch("homeassistant.components.evohome.ev1.EvohomeClient", return_value=None),
|
|
patch("evohomeasync2.broker.Broker.get", mock_get_factory(install)),
|
|
):
|
|
mock_client.side_effect = EvohomeClient
|
|
|
|
assert await async_setup_component(hass, DOMAIN, {DOMAIN: test_config})
|
|
await hass.async_block_till_done()
|
|
|
|
mock_client.assert_called_once()
|
|
|
|
assert mock_client.call_args.args[0] == test_config[CONF_USERNAME]
|
|
assert mock_client.call_args.args[1] == test_config[CONF_PASSWORD]
|
|
|
|
assert isinstance(mock_client.call_args.kwargs["session"], ClientSession)
|
|
|
|
assert mock_client.account_info is not None
|
|
|
|
return mock_client
|