Skip to content

Commit

Permalink
Test storage save and load for evohome (home-assistant#122510)
Browse files Browse the repository at this point in the history
* test storage save and load

* fix bug exposed by test

* refactor test

* add JSON for test account/location

* create helpers to load JSON

* refactor test

* baseline refactor

* tweak

* update requiremenst

* rationalise code

* remove conditional in test

* refactor test

* mypy fix

* tweak tests

* working test

* working test 4

* working test 5

* add typed dicts

* working dtms

* lint

* fix dtm asserts

* doc strings

* list

* tweak conditional

* tweak test data sets to extend coverage

* leverage conftest.py for subsequent tests

* revert test storage

* revert part two

* rename symbols

* remove anachronism

* stop unwanted DNS lookup

* Clean up type ignores

* Format

---------

Co-authored-by: Martin Hjelmare <[email protected]>
  • Loading branch information
zxdavb and MartinHjelmare authored Aug 3, 2024
1 parent 6684f61 commit bb31fc1
Show file tree
Hide file tree
Showing 11 changed files with 964 additions and 0 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ build.json @home-assistant/supervisor
/homeassistant/components/evil_genius_labs/ @balloob
/tests/components/evil_genius_labs/ @balloob
/homeassistant/components/evohome/ @zxdavb
/tests/components/evohome/ @zxdavb
/homeassistant/components/ezviz/ @RenierM26 @baqs
/tests/components/ezviz/ @RenierM26 @baqs
/homeassistant/components/faa_delays/ @ntilley905
Expand Down
3 changes: 3 additions & 0 deletions requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,9 @@ eternalegypt==0.0.16
# homeassistant.components.eufylife_ble
eufylife-ble-client==0.1.8

# homeassistant.components.evohome
evohome-async==0.4.20

# homeassistant.components.bryant_evolution
evolutionhttp==0.0.18

Expand Down
1 change: 1 addition & 0 deletions tests/components/evohome/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""The tests for the evohome integration."""
111 changes: 111 additions & 0 deletions tests/components/evohome/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"""Fixtures and helpers for the evohome tests."""

from __future__ import annotations

from datetime import datetime, timedelta
from typing import Any, Final
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

from tests.common import load_json_array_fixture, load_json_object_fixture

TEST_CONFIG: Final = {
CONF_USERNAME: "username",
CONF_PASSWORD: "password",
}


def user_account_config_fixture() -> JsonObjectType:
"""Load JSON for the config of a user's account."""
return load_json_object_fixture("user_account.json", DOMAIN)


def user_locations_config_fixture() -> JsonArrayType:
"""Load JSON for the config of a user's installation (a list of locations)."""
return load_json_array_fixture("user_locations.json", DOMAIN)


def location_status_fixture(loc_id: str) -> JsonObjectType:
"""Load JSON for the status of a specific location."""
return load_json_object_fixture(f"status_{loc_id}.json", DOMAIN)


def dhw_schedule_fixture() -> JsonObjectType:
"""Load JSON for the schedule of a domesticHotWater zone."""
return load_json_object_fixture("schedule_dhw.json", DOMAIN)


def zone_schedule_fixture() -> JsonObjectType:
"""Load JSON for the schedule of a temperatureZone zone."""
return load_json_object_fixture("schedule_zone.json", DOMAIN)


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()

if url.startswith("location"):
if "installationInfo" in url: # location/installationInfo?userId={id}
return user_locations_config_fixture()
if "location" in url: # location/{id}/status
return location_status_fixture("2738909")

elif "schedule" in url:
if url.startswith("domesticHotWater"): # domesticHotWater/{id}/schedule
return dhw_schedule_fixture()
if url.startswith("temperatureZone"): # temperatureZone/{id}/schedule
return zone_schedule_fixture()

pytest.xfail(f"Unexpected URL: {url}")


@patch("evohomeasync2.broker.Broker.get", mock_get)
async def setup_evohome(hass: HomeAssistant, test_config: dict[str, str]) -> 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),
):
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
10 changes: 10 additions & 0 deletions tests/components/evohome/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Constants for the evohome tests."""

from __future__ import annotations

from typing import Final

ACCESS_TOKEN: Final = "at_1dc7z657UKzbhKA..."
REFRESH_TOKEN: Final = "rf_jg68ZCKYdxEI3fF..."
SESSION_ID: Final = "F7181186..."
USERNAME: Final = "[email protected]"
81 changes: 81 additions & 0 deletions tests/components/evohome/fixtures/schedule_dhw.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"dailySchedules": [
{
"dayOfWeek": "Monday",
"switchpoints": [
{ "dhwState": "On", "timeOfDay": "06:30:00" },
{ "dhwState": "Off", "timeOfDay": "08:30:00" },
{ "dhwState": "On", "timeOfDay": "12:00:00" },
{ "dhwState": "Off", "timeOfDay": "13:00:00" },
{ "dhwState": "On", "timeOfDay": "16:30:00" },
{ "dhwState": "Off", "timeOfDay": "22:30:00" }
]
},
{
"dayOfWeek": "Tuesday",
"switchpoints": [
{ "dhwState": "On", "timeOfDay": "06:30:00" },
{ "dhwState": "Off", "timeOfDay": "08:30:00" },
{ "dhwState": "On", "timeOfDay": "12:00:00" },
{ "dhwState": "Off", "timeOfDay": "13:00:00" },
{ "dhwState": "On", "timeOfDay": "16:30:00" },
{ "dhwState": "Off", "timeOfDay": "22:30:00" }
]
},
{
"dayOfWeek": "Wednesday",
"switchpoints": [
{ "dhwState": "On", "timeOfDay": "06:30:00" },
{ "dhwState": "Off", "timeOfDay": "08:30:00" },
{ "dhwState": "On", "timeOfDay": "12:00:00" },
{ "dhwState": "Off", "timeOfDay": "13:00:00" },
{ "dhwState": "On", "timeOfDay": "16:30:00" },
{ "dhwState": "Off", "timeOfDay": "22:30:00" }
]
},
{
"dayOfWeek": "Thursday",
"switchpoints": [
{ "dhwState": "On", "timeOfDay": "06:30:00" },
{ "dhwState": "Off", "timeOfDay": "08:30:00" },
{ "dhwState": "On", "timeOfDay": "12:00:00" },
{ "dhwState": "Off", "timeOfDay": "13:00:00" },
{ "dhwState": "On", "timeOfDay": "16:30:00" },
{ "dhwState": "Off", "timeOfDay": "22:30:00" }
]
},
{
"dayOfWeek": "Friday",
"switchpoints": [
{ "dhwState": "On", "timeOfDay": "06:30:00" },
{ "dhwState": "Off", "timeOfDay": "08:30:00" },
{ "dhwState": "On", "timeOfDay": "12:00:00" },
{ "dhwState": "Off", "timeOfDay": "13:00:00" },
{ "dhwState": "On", "timeOfDay": "16:30:00" },
{ "dhwState": "Off", "timeOfDay": "22:30:00" }
]
},
{
"dayOfWeek": "Saturday",
"switchpoints": [
{ "dhwState": "On", "timeOfDay": "06:30:00" },
{ "dhwState": "Off", "timeOfDay": "09:30:00" },
{ "dhwState": "On", "timeOfDay": "12:00:00" },
{ "dhwState": "Off", "timeOfDay": "13:00:00" },
{ "dhwState": "On", "timeOfDay": "16:30:00" },
{ "dhwState": "Off", "timeOfDay": "23:00:00" }
]
},
{
"dayOfWeek": "Sunday",
"switchpoints": [
{ "dhwState": "On", "timeOfDay": "06:30:00" },
{ "dhwState": "Off", "timeOfDay": "09:30:00" },
{ "dhwState": "On", "timeOfDay": "12:00:00" },
{ "dhwState": "Off", "timeOfDay": "13:00:00" },
{ "dhwState": "On", "timeOfDay": "16:30:00" },
{ "dhwState": "Off", "timeOfDay": "23:00:00" }
]
}
]
}
67 changes: 67 additions & 0 deletions tests/components/evohome/fixtures/schedule_zone.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"dailySchedules": [
{
"dayOfWeek": "Monday",
"switchpoints": [
{ "heatSetpoint": 18.1, "timeOfDay": "07:00:00" },
{ "heatSetpoint": 16.0, "timeOfDay": "08:00:00" },
{ "heatSetpoint": 18.6, "timeOfDay": "22:10:00" },
{ "heatSetpoint": 15.9, "timeOfDay": "23:00:00" }
]
},
{
"dayOfWeek": "Tuesday",
"switchpoints": [
{ "heatSetpoint": 18.1, "timeOfDay": "07:00:00" },
{ "heatSetpoint": 16.0, "timeOfDay": "08:00:00" },
{ "heatSetpoint": 18.6, "timeOfDay": "22:10:00" },
{ "heatSetpoint": 15.9, "timeOfDay": "23:00:00" }
]
},
{
"dayOfWeek": "Wednesday",
"switchpoints": [
{ "heatSetpoint": 18.1, "timeOfDay": "07:00:00" },
{ "heatSetpoint": 16.0, "timeOfDay": "08:00:00" },
{ "heatSetpoint": 18.6, "timeOfDay": "22:10:00" },
{ "heatSetpoint": 15.9, "timeOfDay": "23:00:00" }
]
},
{
"dayOfWeek": "Thursday",
"switchpoints": [
{ "heatSetpoint": 18.1, "timeOfDay": "07:00:00" },
{ "heatSetpoint": 16.0, "timeOfDay": "08:00:00" },
{ "heatSetpoint": 18.6, "timeOfDay": "22:10:00" },
{ "heatSetpoint": 15.9, "timeOfDay": "23:00:00" }
]
},
{
"dayOfWeek": "Friday",
"switchpoints": [
{ "heatSetpoint": 18.1, "timeOfDay": "07:00:00" },
{ "heatSetpoint": 16.0, "timeOfDay": "08:00:00" },
{ "heatSetpoint": 18.6, "timeOfDay": "22:10:00" },
{ "heatSetpoint": 15.9, "timeOfDay": "23:00:00" }
]
},
{
"dayOfWeek": "Saturday",
"switchpoints": [
{ "heatSetpoint": 18.5, "timeOfDay": "07:00:00" },
{ "heatSetpoint": 16.0, "timeOfDay": "08:30:00" },
{ "heatSetpoint": 18.6, "timeOfDay": "22:10:00" },
{ "heatSetpoint": 15.9, "timeOfDay": "23:00:00" }
]
},
{
"dayOfWeek": "Sunday",
"switchpoints": [
{ "heatSetpoint": 18.5, "timeOfDay": "07:00:00" },
{ "heatSetpoint": 16.0, "timeOfDay": "08:30:00" },
{ "heatSetpoint": 18.6, "timeOfDay": "22:10:00" },
{ "heatSetpoint": 15.9, "timeOfDay": "23:00:00" }
]
}
]
}
Loading

0 comments on commit bb31fc1

Please sign in to comment.