Refactor all Sensibo tests (#134478)

* Add me json

* Mods

* Mods

* More

* Mods

* Mods

* clean

* last bits

* Fix

* unique id

* return_value

* remove blocking

* Fix rebase
This commit is contained in:
G Johansson 2025-01-03 12:44:47 +01:00 committed by GitHub
parent 19852ecc24
commit 36582f9ac2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 1398 additions and 1880 deletions

View File

@ -2,16 +2,15 @@
from __future__ import annotations from __future__ import annotations
from collections.abc import AsyncGenerator, Generator
import json import json
from typing import Any from typing import Any
from unittest.mock import patch from unittest.mock import AsyncMock, MagicMock, patch
from pysensibo import SensiboClient from pysensibo import APIV1, APIV2, SensiboClient, SensiboData
from pysensibo.model import SensiboData
import pytest import pytest
from homeassistant.components.sensibo.const import DOMAIN, PLATFORMS from homeassistant.components.sensibo.const import DOMAIN, PLATFORMS
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -21,6 +20,15 @@ from tests.common import MockConfigEntry, load_fixture
from tests.test_util.aiohttp import AiohttpClientMocker from tests.test_util.aiohttp import AiohttpClientMocker
@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.sensibo.async_setup_entry", return_value=True
) as mock_setup_entry:
yield mock_setup_entry
@pytest.fixture(name="load_platforms") @pytest.fixture(name="load_platforms")
async def patch_platform_constant() -> list[Platform]: async def patch_platform_constant() -> list[Platform]:
"""Return list of platforms to load.""" """Return list of platforms to load."""
@ -30,63 +38,81 @@ async def patch_platform_constant() -> list[Platform]:
@pytest.fixture @pytest.fixture
async def load_int( async def load_int(
hass: HomeAssistant, hass: HomeAssistant,
get_data: SensiboData, mock_client: SensiboClient,
load_platforms: list[Platform], load_platforms: list[Platform],
) -> MockConfigEntry: ) -> MockConfigEntry:
"""Set up the Sensibo integration in Home Assistant.""" """Set up the Sensibo integration."""
config_entry = MockConfigEntry( config_entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
source=SOURCE_USER,
data=ENTRY_CONFIG, data=ENTRY_CONFIG,
entry_id="1", entry_id="1",
unique_id="username", unique_id="firstnamelastname",
version=2, version=2,
) )
config_entry.add_to_hass(hass) config_entry.add_to_hass(hass)
with ( with patch("homeassistant.components.sensibo.PLATFORMS", load_platforms):
patch("homeassistant.components.sensibo.PLATFORMS", load_platforms),
patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=get_data,
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]},
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
),
):
await hass.config_entries.async_setup(config_entry.entry_id) await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
return config_entry return config_entry
@pytest.fixture(name="mock_client")
async def get_client(
hass: HomeAssistant,
get_data: tuple[SensiboData, dict[str, Any]],
) -> AsyncGenerator[MagicMock]:
"""Mock SensiboClient."""
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient",
autospec=True,
) as mock_client:
client = mock_client.return_value
client.async_get_devices_data.return_value = get_data[0]
client.async_get_me.return_value = get_data[1]
yield client
@pytest.fixture(name="get_data") @pytest.fixture(name="get_data")
async def get_data_from_library( async def get_data_from_library(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, load_json: dict[str, Any] hass: HomeAssistant,
) -> SensiboData: aioclient_mock: AiohttpClientMocker,
"""Retrieve data from upstream Sensibo library.""" load_json: tuple[dict[str, Any], dict[str, Any]],
) -> AsyncGenerator[tuple[SensiboData, dict[str, Any]]]:
client = SensiboClient("123467890", aioclient_mock.create_session(hass.loop)) """Get data from api."""
with patch("pysensibo.SensiboClient.async_get_devices", return_value=load_json): aioclient_mock.request(
output = await client.async_get_devices_data() "GET",
url=APIV1 + "/users/me",
params={"apiKey": "1234567890"},
json=load_json[1],
)
aioclient_mock.request(
"GET",
url=APIV2 + "/users/me/pods",
params={"apiKey": "1234567890", "fields": "*"},
json=load_json[0],
)
client = SensiboClient("1234567890", aioclient_mock.create_session(hass.loop))
me = await client.async_get_me()
data = await client.async_get_devices_data()
yield (data, me)
await client._session.close() await client._session.close()
return output
@pytest.fixture(name="load_json") @pytest.fixture(name="load_json")
def load_json_from_fixture(load_data: str) -> SensiboData: def load_json_from_fixture(
load_data: tuple[str, str],
) -> tuple[dict[str, Any], dict[str, Any]]:
"""Load fixture with json data and return.""" """Load fixture with json data and return."""
json_data: dict[str, Any] = json.loads(load_data) json_data: dict[str, Any] = json.loads(load_data[0])
return json_data json_me: dict[str, Any] = json.loads(load_data[1])
return (json_data, json_me)
@pytest.fixture(name="load_data", scope="package") @pytest.fixture(name="load_data", scope="package")
def load_data_from_fixture() -> str: def load_data_from_fixture() -> tuple[str, str]:
"""Load fixture with fixture data and return.""" """Load fixture with fixture data and return."""
return load_fixture("data.json", "sensibo") return (load_fixture("data.json", "sensibo"), load_fixture("me.json", "sensibo"))

View File

@ -0,0 +1,13 @@
{
"status": "success",
"result": {
"username": "firstnamelastname",
"email": "first.last@domain.com",
"firstName": "Firstname",
"lastName": "Lastname",
"temperatureUnit": "C",
"appRegistrationSource": "Sensibo",
"organization": null,
"availableOrganizations": []
}
}

View File

@ -0,0 +1,137 @@
# serializer version: 1
# name: test_device
list([
DeviceRegistryEntrySnapshot({
'area_id': 'hallway',
'config_entries': <ANY>,
'configuration_url': 'https://home.sensibo.com/',
'connections': set({
tuple(
'mac',
'00:02:00:b6:00:00',
),
}),
'disabled_by': None,
'entry_type': None,
'hw_version': 'esp8266ex',
'id': <ANY>,
'identifiers': set({
tuple(
'sensibo',
'ABC999111',
),
}),
'is_new': False,
'labels': set({
}),
'manufacturer': 'Sensibo',
'model': 'skyv2',
'model_id': None,
'name': 'Hallway',
'name_by_user': None,
'primary_config_entry': <ANY>,
'serial_number': '1234567890',
'suggested_area': 'Hallway',
'sw_version': 'SKY30046',
'via_device_id': None,
}),
DeviceRegistryEntrySnapshot({
'area_id': 'kitchen',
'config_entries': <ANY>,
'configuration_url': 'https://home.sensibo.com/',
'connections': set({
tuple(
'mac',
'00:01:00:01:00:01',
),
}),
'disabled_by': None,
'entry_type': None,
'hw_version': 'pure-esp32',
'id': <ANY>,
'identifiers': set({
tuple(
'sensibo',
'AAZZAAZZ',
),
}),
'is_new': False,
'labels': set({
}),
'manufacturer': 'Sensibo',
'model': 'pure',
'model_id': None,
'name': 'Kitchen',
'name_by_user': None,
'primary_config_entry': <ANY>,
'serial_number': '0987654321',
'suggested_area': 'Kitchen',
'sw_version': 'PUR00111',
'via_device_id': None,
}),
DeviceRegistryEntrySnapshot({
'area_id': 'bedroom',
'config_entries': <ANY>,
'configuration_url': 'https://home.sensibo.com/',
'connections': set({
tuple(
'mac',
'00:03:00:03:00:03',
),
}),
'disabled_by': None,
'entry_type': None,
'hw_version': 'pure-esp32',
'id': <ANY>,
'identifiers': set({
tuple(
'sensibo',
'BBZZBBZZ',
),
}),
'is_new': False,
'labels': set({
}),
'manufacturer': 'Sensibo',
'model': 'pure',
'model_id': None,
'name': 'Bedroom',
'name_by_user': None,
'primary_config_entry': <ANY>,
'serial_number': '0987654329',
'suggested_area': 'Bedroom',
'sw_version': 'PUR00111',
'via_device_id': None,
}),
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entries': <ANY>,
'configuration_url': 'https://home.sensibo.com/',
'connections': set({
}),
'disabled_by': None,
'entry_type': None,
'hw_version': 'nrf52',
'id': <ANY>,
'identifiers': set({
tuple(
'sensibo',
'AABBCC',
),
}),
'is_new': False,
'labels': set({
}),
'manufacturer': 'Sensibo',
'model': 'motion_sensor',
'model_id': None,
'name': 'Hallway Motion Sensor',
'name_by_user': None,
'primary_config_entry': <ANY>,
'serial_number': None,
'suggested_area': None,
'sw_version': 'V17',
'via_device_id': <ANY>,
}),
])
# ---

View File

@ -3,9 +3,11 @@
from __future__ import annotations from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from typing import Any
from unittest.mock import patch from unittest.mock import patch
from pysensibo.model import SensiboData from freezegun.api import FrozenDateTimeFactory
from pysensibo import SensiboData
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
@ -13,7 +15,6 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_OFF, STATE_ON, Platform from homeassistant.const import STATE_OFF, STATE_ON, Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.util import dt as dt_util
from tests.common import async_fire_time_changed, snapshot_platform from tests.common import async_fire_time_changed, snapshot_platform
@ -27,29 +28,31 @@ async def test_binary_sensor(
hass: HomeAssistant, hass: HomeAssistant,
load_int: ConfigEntry, load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
get_data: SensiboData, get_data: tuple[SensiboData, dict[str, Any]],
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test the Sensibo binary sensor.""" """Test the Sensibo binary sensor."""
await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id) await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id)
monkeypatch.setattr( monkeypatch.setattr(
get_data.parsed["ABC999111"].motion_sensors["AABBCC"], "motion", False get_data[0].parsed["ABC999111"].motion_sensors["AABBCC"], "motion", False
) )
with patch( with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", "homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=get_data, return_value=get_data,
): ):
async_fire_time_changed( freezer.tick(timedelta(minutes=5))
hass, async_fire_time_changed(hass)
dt_util.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done() await hass.async_block_till_done()
state1 = hass.states.get("binary_sensor.hallway_motion_sensor_connectivity") assert (
state3 = hass.states.get("binary_sensor.hallway_motion_sensor_motion") hass.states.get("binary_sensor.hallway_motion_sensor_connectivity").state
assert state1.state == STATE_ON == STATE_ON
assert state3.state == STATE_OFF )
assert (
hass.states.get("binary_sensor.hallway_motion_sensor_motion").state == STATE_OFF
)

View File

@ -2,12 +2,13 @@
from __future__ import annotations from __future__ import annotations
from datetime import datetime, timedelta from datetime import timedelta
from unittest.mock import patch from typing import Any
from unittest.mock import MagicMock
from freezegun import freeze_time from freezegun import freeze_time
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
from pysensibo.model import SensiboData from pysensibo import SensiboData
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
@ -45,14 +46,20 @@ async def test_button(
await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id) await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
@pytest.mark.parametrize(
"load_platforms",
[[Platform.BINARY_SENSOR, Platform.BUTTON, Platform.SENSOR]],
)
async def test_button_update( async def test_button_update(
hass: HomeAssistant, hass: HomeAssistant,
load_int: ConfigEntry, load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
get_data: SensiboData, mock_client: MagicMock,
get_data: tuple[SensiboData, dict[str, Any]],
freezer: FrozenDateTimeFactory, freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test the Sensibo button.""" """Test the Sensibo button press."""
state_button = hass.states.get("button.hallway_reset_filter") state_button = hass.states.get("button.hallway_reset_filter")
state_filter_clean = hass.states.get("binary_sensor.hallway_filter_clean_required") state_filter_clean = hass.states.get("binary_sensor.hallway_filter_clean_required")
@ -62,48 +69,32 @@ async def test_button_update(
assert state_filter_clean.state is STATE_ON assert state_filter_clean.state is STATE_ON
assert state_filter_last_reset.state == "2022-03-12T15:24:26+00:00" assert state_filter_last_reset.state == "2022-03-12T15:24:26+00:00"
today = datetime(datetime.now().year + 1, 6, 19, 20, 0, 0).replace( today = dt_util.utcnow() + timedelta(minutes=10)
tzinfo=dt_util.UTC today = today.replace(microsecond=0)
) today_str = today.isoformat(timespec="seconds")
today_str = today.isoformat()
freezer.move_to(today) freezer.move_to(today)
with ( mock_client.async_reset_filter.return_value = {"status": "success"}
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data",
return_value=get_data,
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_reset_filter",
return_value={"status": "success"},
),
):
await hass.services.async_call(
BUTTON_DOMAIN,
SERVICE_PRESS,
{
ATTR_ENTITY_ID: state_button.entity_id,
},
blocking=True,
)
await hass.async_block_till_done()
monkeypatch.setattr(get_data.parsed["ABC999111"], "filter_clean", False) await hass.services.async_call(
BUTTON_DOMAIN,
SERVICE_PRESS,
{
ATTR_ENTITY_ID: state_button.entity_id,
},
blocking=True,
)
monkeypatch.setattr(get_data[0].parsed["ABC999111"], "filter_clean", False)
monkeypatch.setattr( monkeypatch.setattr(
get_data.parsed["ABC999111"], get_data[0].parsed["ABC999111"],
"filter_last_reset", "filter_last_reset",
today, today,
) )
with patch( freezer.tick(timedelta(minutes=5))
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", async_fire_time_changed(hass)
return_value=get_data, await hass.async_block_till_done()
):
async_fire_time_changed(
hass,
dt_util.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state_button = hass.states.get("button.hallway_reset_filter") state_button = hass.states.get("button.hallway_reset_filter")
state_filter_clean = hass.states.get("binary_sensor.hallway_filter_clean_required") state_filter_clean = hass.states.get("binary_sensor.hallway_filter_clean_required")
@ -116,31 +107,22 @@ async def test_button_update(
async def test_button_failure( async def test_button_failure(
hass: HomeAssistant, hass: HomeAssistant,
load_int: ConfigEntry, load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch, mock_client: MagicMock,
get_data: SensiboData,
) -> None: ) -> None:
"""Test the Sensibo button fails.""" """Test the Sensibo button failure."""
state_button = hass.states.get("button.hallway_reset_filter") state = hass.states.get("button.hallway_reset_filter")
with ( mock_client.async_reset_filter.return_value = {"status": "failure"}
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", with pytest.raises(
return_value=get_data, HomeAssistantError,
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_reset_filter",
return_value={"status": "failure"},
),
pytest.raises(
HomeAssistantError,
),
): ):
await hass.services.async_call( await hass.services.async_call(
BUTTON_DOMAIN, BUTTON_DOMAIN,
SERVICE_PRESS, SERVICE_PRESS,
{ {
ATTR_ENTITY_ID: state_button.entity_id, ATTR_ENTITY_ID: state.entity_id,
}, },
blocking=True, blocking=True,
) )

File diff suppressed because it is too large Load Diff

View File

@ -3,24 +3,26 @@
from __future__ import annotations from __future__ import annotations
from typing import Any from typing import Any
from unittest.mock import patch from unittest.mock import AsyncMock, MagicMock, patch
import aiohttp from pysensibo import AuthenticationError, SensiboError
from pysensibo.exceptions import AuthenticationError, SensiboError
import pytest import pytest
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.sensibo.const import DOMAIN
from homeassistant.const import CONF_API_KEY from homeassistant.const import CONF_API_KEY
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
DOMAIN = "sensibo" pytestmark = pytest.mark.usefixtures("mock_setup_entry")
async def test_form(hass: HomeAssistant) -> None: async def test_basic_setup(
"""Test we get the form.""" hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_client: MagicMock
) -> None:
"""Test we get and complete the form."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER} DOMAIN, context={"source": config_entries.SOURCE_USER}
@ -29,32 +31,20 @@ async def test_form(hass: HomeAssistant) -> None:
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["errors"] == {} assert result["errors"] == {}
with ( result = await hass.config_entries.flow.async_configure(
patch( result["flow_id"],
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices", {
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]}, CONF_API_KEY: "1234567890",
), },
patch( )
"homeassistant.components.sensibo.util.SensiboClient.async_get_me", await hass.async_block_till_done()
return_value={"result": {"username": "username"}},
),
patch(
"homeassistant.components.sensibo.async_setup_entry",
return_value=True,
) as mock_setup_entry,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_API_KEY: "1234567890",
},
)
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result2["version"] == 2 assert result["version"] == 2
assert result2["data"] == { assert result["title"] == "firstnamelastname"
"api_key": "1234567890", assert result["result"].unique_id == "firstnamelastname"
assert result["data"] == {
CONF_API_KEY: "1234567890",
} }
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
@ -63,14 +53,12 @@ async def test_form(hass: HomeAssistant) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
("error_message", "p_error"), ("error_message", "p_error"),
[ [
(aiohttp.ClientConnectionError, "cannot_connect"),
(TimeoutError, "cannot_connect"),
(AuthenticationError, "invalid_auth"), (AuthenticationError, "invalid_auth"),
(SensiboError, "cannot_connect"), (SensiboError, "cannot_connect"),
], ],
) )
async def test_flow_fails( async def test_flow_fails(
hass: HomeAssistant, error_message: Exception, p_error: str hass: HomeAssistant, mock_client: MagicMock, error_message: Exception, p_error: str
) -> None: ) -> None:
"""Test config flow errors.""" """Test config flow errors."""
@ -85,44 +73,30 @@ async def test_flow_fails(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices", "homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
side_effect=error_message, side_effect=error_message,
): ):
result2 = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
user_input={ user_input={
CONF_API_KEY: "1234567890", CONF_API_KEY: "1234567890",
}, },
) )
assert result2["errors"] == {"base": p_error} assert result["errors"] == {"base": p_error}
with ( result = await hass.config_entries.flow.async_configure(
patch( result["flow_id"],
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices", user_input={
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]}, CONF_API_KEY: "1234567890",
), },
patch( )
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
),
patch(
"homeassistant.components.sensibo.async_setup_entry",
return_value=True,
),
):
result3 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_API_KEY: "1234567891",
},
)
assert result3["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result3["title"] == "username" assert result["title"] == "firstnamelastname"
assert result3["data"] == { assert result["data"] == {
"api_key": "1234567891", CONF_API_KEY: "1234567890",
} }
async def test_flow_get_no_devices(hass: HomeAssistant) -> None: async def test_flow_get_no_devices(hass: HomeAssistant, mock_client: MagicMock) -> None:
"""Test config flow get no devices from api.""" """Test config flow get no devices from api."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -132,27 +106,36 @@ async def test_flow_get_no_devices(hass: HomeAssistant) -> None:
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["step_id"] == config_entries.SOURCE_USER assert result["step_id"] == config_entries.SOURCE_USER
with ( with patch(
patch( "homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices", return_value={"result": {}},
return_value={"result": []},
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {}},
),
): ):
result2 = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
user_input={ user_input={
CONF_API_KEY: "1234567890", CONF_API_KEY: "1234567890",
}, },
) )
assert result2["errors"] == {"base": "no_devices"} assert result["errors"] == {"base": "no_devices"}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_API_KEY: "1234567890",
},
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "firstnamelastname"
assert result["data"] == {
CONF_API_KEY: "1234567890",
}
async def test_flow_get_no_username(hass: HomeAssistant) -> None: async def test_flow_get_no_username(
hass: HomeAssistant, mock_client: MagicMock
) -> None:
"""Test config flow get no username from api.""" """Test config flow get no username from api."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -162,15 +145,9 @@ async def test_flow_get_no_username(hass: HomeAssistant) -> None:
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["step_id"] == config_entries.SOURCE_USER assert result["step_id"] == config_entries.SOURCE_USER
with ( with patch(
patch( "homeassistant.components.sensibo.util.SensiboClient.async_get_me",
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices", return_value={"result": {}},
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]},
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {}},
),
): ):
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
@ -181,14 +158,27 @@ async def test_flow_get_no_username(hass: HomeAssistant) -> None:
assert result2["errors"] == {"base": "no_username"} assert result2["errors"] == {"base": "no_username"}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_API_KEY: "1234567890",
},
)
async def test_reauth_flow(hass: HomeAssistant) -> None: assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "firstnamelastname"
assert result["data"] == {
CONF_API_KEY: "1234567890",
}
async def test_reauth_flow(hass: HomeAssistant, mock_client: MagicMock) -> None:
"""Test a reauthentication flow.""" """Test a reauthentication flow."""
entry = MockConfigEntry( entry = MockConfigEntry(
version=2, version=2,
domain=DOMAIN, domain=DOMAIN,
unique_id="username", unique_id="firstnamelastname",
data={"api_key": "1234567890"}, data={CONF_API_KEY: "1234567890"},
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
@ -197,52 +187,33 @@ async def test_reauth_flow(hass: HomeAssistant) -> None:
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["errors"] == {} assert result["errors"] == {}
with ( result = await hass.config_entries.flow.async_configure(
patch( result["flow_id"],
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices", {CONF_API_KEY: "1234567890"},
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]}, )
), await hass.async_block_till_done()
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
) as mock_sensibo,
patch(
"homeassistant.components.sensibo.async_setup_entry",
return_value=True,
) as mock_setup_entry,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_API_KEY: "1234567891"},
)
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.ABORT assert result["type"] is FlowResultType.ABORT
assert result2["reason"] == "reauth_successful" assert result["reason"] == "reauth_successful"
assert entry.data == {"api_key": "1234567891"} assert entry.data == {CONF_API_KEY: "1234567890"}
assert len(mock_sensibo.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
@pytest.mark.parametrize( @pytest.mark.parametrize(
("sideeffect", "p_error"), ("sideeffect", "p_error"),
[ [
(aiohttp.ClientConnectionError, "cannot_connect"),
(TimeoutError, "cannot_connect"),
(AuthenticationError, "invalid_auth"), (AuthenticationError, "invalid_auth"),
(SensiboError, "cannot_connect"), (SensiboError, "cannot_connect"),
], ],
) )
async def test_reauth_flow_error( async def test_reauth_flow_error(
hass: HomeAssistant, sideeffect: Exception, p_error: str hass: HomeAssistant, sideeffect: Exception, p_error: str, mock_client: MagicMock
) -> None: ) -> None:
"""Test a reauthentication flow with error.""" """Test a reauthentication flow with error."""
entry = MockConfigEntry( entry = MockConfigEntry(
version=2, version=2,
domain=DOMAIN, domain=DOMAIN,
unique_id="username", unique_id="firstnamelastname",
data={"api_key": "1234567890"}, data={CONF_API_KEY: "1234567890"},
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
@ -252,39 +223,25 @@ async def test_reauth_flow_error(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices", "homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
side_effect=sideeffect, side_effect=sideeffect,
): ):
result2 = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{CONF_API_KEY: "1234567890"}, {CONF_API_KEY: "1234567890"},
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert result2["step_id"] == "reauth_confirm" assert result["step_id"] == "reauth_confirm"
assert result2["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result2["errors"] == {"base": p_error} assert result["errors"] == {"base": p_error}
with ( result = await hass.config_entries.flow.async_configure(
patch( result["flow_id"],
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices", {CONF_API_KEY: "1234567890"},
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]}, )
), await hass.async_block_till_done()
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
),
patch(
"homeassistant.components.sensibo.async_setup_entry",
return_value=True,
),
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_API_KEY: "1234567891"},
)
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.ABORT assert result["type"] is FlowResultType.ABORT
assert result2["reason"] == "reauth_successful" assert result["reason"] == "reauth_successful"
assert entry.data == {"api_key": "1234567891"} assert entry.data == {CONF_API_KEY: "1234567890"}
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -297,12 +254,12 @@ async def test_reauth_flow_error(
), ),
( (
{"result": []}, {"result": []},
{"result": {"username": "username"}}, {"result": {"username": "firstnamelastname"}},
"no_devices", "no_devices",
), ),
( (
{"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]}, {"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]},
{"result": {"username": "username2"}}, {"result": {"username": "firstnamelastname2"}},
"incorrect_api_key", "incorrect_api_key",
), ),
], ],
@ -312,13 +269,14 @@ async def test_flow_reauth_no_username_or_device(
get_devices: dict[str, Any], get_devices: dict[str, Any],
get_me: dict[str, Any], get_me: dict[str, Any],
p_error: str, p_error: str,
mock_client: MagicMock,
) -> None: ) -> None:
"""Test config flow get no username from api.""" """Test reauth flow with errors from api."""
entry = MockConfigEntry( entry = MockConfigEntry(
version=2, version=2,
domain=DOMAIN, domain=DOMAIN,
unique_id="username", unique_id="firstnamelastname",
data={"api_key": "1234567890"}, data={CONF_API_KEY: "1234567890"},
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
@ -337,7 +295,7 @@ async def test_flow_reauth_no_username_or_device(
return_value=get_me, return_value=get_me,
), ),
): ):
result2 = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
user_input={ user_input={
CONF_API_KEY: "1234567890", CONF_API_KEY: "1234567890",
@ -345,18 +303,28 @@ async def test_flow_reauth_no_username_or_device(
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert result2["step_id"] == "reauth_confirm" assert result["step_id"] == "reauth_confirm"
assert result2["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result2["errors"] == {"base": p_error} assert result["errors"] == {"base": p_error}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_API_KEY: "1234567890"},
)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "reauth_successful"
assert entry.data == {CONF_API_KEY: "1234567890"}
async def test_reconfigure_flow(hass: HomeAssistant) -> None: async def test_reconfigure_flow(hass: HomeAssistant, mock_client: MagicMock) -> None:
"""Test a reconfigure flow.""" """Test a reconfigure flow."""
entry = MockConfigEntry( entry = MockConfigEntry(
version=2, version=2,
domain=DOMAIN, domain=DOMAIN,
unique_id="username", unique_id="firstnamelastname",
data={"api_key": "1234567890"}, data={CONF_API_KEY: "1234567890"},
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
@ -365,52 +333,33 @@ async def test_reconfigure_flow(hass: HomeAssistant) -> None:
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["errors"] == {} assert result["errors"] == {}
with ( result = await hass.config_entries.flow.async_configure(
patch( result["flow_id"],
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices", {CONF_API_KEY: "1234567890"},
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]}, )
), await hass.async_block_till_done()
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
) as mock_sensibo,
patch(
"homeassistant.components.sensibo.async_setup_entry",
return_value=True,
) as mock_setup_entry,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_API_KEY: "1234567891"},
)
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.ABORT assert result["type"] is FlowResultType.ABORT
assert result2["reason"] == "reconfigure_successful" assert result["reason"] == "reconfigure_successful"
assert entry.data == {"api_key": "1234567891"} assert entry.data == {CONF_API_KEY: "1234567890"}
assert len(mock_sensibo.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
@pytest.mark.parametrize( @pytest.mark.parametrize(
("sideeffect", "p_error"), ("sideeffect", "p_error"),
[ [
(aiohttp.ClientConnectionError, "cannot_connect"),
(TimeoutError, "cannot_connect"),
(AuthenticationError, "invalid_auth"), (AuthenticationError, "invalid_auth"),
(SensiboError, "cannot_connect"), (SensiboError, "cannot_connect"),
], ],
) )
async def test_reconfigure_flow_error( async def test_reconfigure_flow_error(
hass: HomeAssistant, sideeffect: Exception, p_error: str hass: HomeAssistant, sideeffect: Exception, p_error: str, mock_client: MagicMock
) -> None: ) -> None:
"""Test a reconfigure flow with error.""" """Test a reconfigure flow with error."""
entry = MockConfigEntry( entry = MockConfigEntry(
version=2, version=2,
domain=DOMAIN, domain=DOMAIN,
unique_id="username", unique_id="firstnamelastname",
data={"api_key": "1234567890"}, data={CONF_API_KEY: "1234567890"},
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
@ -420,39 +369,25 @@ async def test_reconfigure_flow_error(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices", "homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
side_effect=sideeffect, side_effect=sideeffect,
): ):
result2 = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{CONF_API_KEY: "1234567890"}, {CONF_API_KEY: "1234567890"},
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert result2["step_id"] == "reconfigure" assert result["step_id"] == "reconfigure"
assert result2["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result2["errors"] == {"base": p_error} assert result["errors"] == {"base": p_error}
with ( result = await hass.config_entries.flow.async_configure(
patch( result["flow_id"],
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices", {CONF_API_KEY: "1234567890"},
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]}, )
), await hass.async_block_till_done()
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
),
patch(
"homeassistant.components.sensibo.async_setup_entry",
return_value=True,
),
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_API_KEY: "1234567891"},
)
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.ABORT assert result["type"] is FlowResultType.ABORT
assert result2["reason"] == "reconfigure_successful" assert result["reason"] == "reconfigure_successful"
assert entry.data == {"api_key": "1234567891"} assert entry.data == {CONF_API_KEY: "1234567890"}
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -465,12 +400,12 @@ async def test_reconfigure_flow_error(
), ),
( (
{"result": []}, {"result": []},
{"result": {"username": "username"}}, {"result": {"username": "firstnamelastname"}},
"no_devices", "no_devices",
), ),
( (
{"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]}, {"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]},
{"result": {"username": "username2"}}, {"result": {"username": "firstnamelastname2"}},
"incorrect_api_key", "incorrect_api_key",
), ),
], ],
@ -480,13 +415,14 @@ async def test_flow_reconfigure_no_username_or_device(
get_devices: dict[str, Any], get_devices: dict[str, Any],
get_me: dict[str, Any], get_me: dict[str, Any],
p_error: str, p_error: str,
mock_client: MagicMock,
) -> None: ) -> None:
"""Test config flow get no username from api.""" """Test reconfigure flow with errors from api."""
entry = MockConfigEntry( entry = MockConfigEntry(
version=2, version=2,
domain=DOMAIN, domain=DOMAIN,
unique_id="username", unique_id="firstnamelastname",
data={"api_key": "1234567890"}, data={CONF_API_KEY: "1234567890"},
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
@ -505,7 +441,7 @@ async def test_flow_reconfigure_no_username_or_device(
return_value=get_me, return_value=get_me,
), ),
): ):
result2 = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
user_input={ user_input={
CONF_API_KEY: "1234567890", CONF_API_KEY: "1234567890",
@ -513,6 +449,16 @@ async def test_flow_reconfigure_no_username_or_device(
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert result2["step_id"] == "reconfigure" assert result["step_id"] == "reconfigure"
assert result2["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result2["errors"] == {"base": p_error} assert result["errors"] == {"base": p_error}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_API_KEY: "1234567890"},
)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "reconfigure_successful"
assert entry.data == {CONF_API_KEY: "1234567890"}

View File

@ -3,17 +3,18 @@
from __future__ import annotations from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from unittest.mock import patch from typing import Any
from unittest.mock import MagicMock
from freezegun.api import FrozenDateTimeFactory
from pysensibo.exceptions import AuthenticationError, SensiboError from pysensibo.exceptions import AuthenticationError, SensiboError
from pysensibo.model import SensiboData from pysensibo.model import SensiboData
import pytest import pytest
from homeassistant.components.climate import HVACMode
from homeassistant.components.sensibo.const import DOMAIN from homeassistant.components.sensibo.const import DOMAIN
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import STATE_UNAVAILABLE from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.util import dt as dt_util
from . import ENTRY_CONFIG from . import ENTRY_CONFIG
@ -21,75 +22,71 @@ from tests.common import MockConfigEntry, async_fire_time_changed
async def test_coordinator( async def test_coordinator(
hass: HomeAssistant, monkeypatch: pytest.MonkeyPatch, get_data: SensiboData hass: HomeAssistant,
monkeypatch: pytest.MonkeyPatch,
mock_client: MagicMock,
get_data: tuple[SensiboData, dict[str, Any]],
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test the Sensibo coordinator with errors.""" """Test the Sensibo coordinator with errors."""
config_entry = MockConfigEntry( config_entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
source=SOURCE_USER,
data=ENTRY_CONFIG, data=ENTRY_CONFIG,
entry_id="1", entry_id="1",
unique_id="username", unique_id="firstnamelastname",
version=2, version=2,
) )
config_entry.add_to_hass(hass) config_entry.add_to_hass(hass)
with ( monkeypatch.setattr(get_data[0].parsed["ABC999111"], "hvac_mode", "heat")
patch( monkeypatch.setattr(get_data[0].parsed["ABC999111"], "device_on", True)
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
) as mock_data,
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]},
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
),
):
monkeypatch.setattr(get_data.parsed["ABC999111"], "hvac_mode", "heat")
monkeypatch.setattr(get_data.parsed["ABC999111"], "device_on", True)
mock_data.return_value = get_data
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
mock_data.assert_called_once()
state = hass.states.get("climate.hallway")
assert state.state == "heat"
mock_data.reset_mock()
mock_data.side_effect = SensiboError("info") mock_data = mock_client.async_get_devices_data
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=1)) mock_data.return_value = get_data[0]
await hass.async_block_till_done() await hass.config_entries.async_setup(config_entry.entry_id)
mock_data.assert_called_once() await hass.async_block_till_done()
state = hass.states.get("climate.hallway") mock_data.assert_called_once()
assert state.state == STATE_UNAVAILABLE state = hass.states.get("climate.hallway")
mock_data.reset_mock() assert state.state == HVACMode.HEAT
mock_data.reset_mock()
mock_data.return_value = SensiboData(raw={}, parsed={}) mock_data.side_effect = SensiboError("info")
mock_data.side_effect = None freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=3)) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done()
mock_data.assert_called_once() mock_data.assert_called_once()
state = hass.states.get("climate.hallway") state = hass.states.get("climate.hallway")
assert state.state == STATE_UNAVAILABLE assert state.state == STATE_UNAVAILABLE
mock_data.reset_mock() mock_data.reset_mock()
monkeypatch.setattr(get_data.parsed["ABC999111"], "hvac_mode", "heat") mock_data.return_value = SensiboData(raw={}, parsed={})
monkeypatch.setattr(get_data.parsed["ABC999111"], "device_on", True) mock_data.side_effect = None
freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
mock_data.assert_called_once()
state = hass.states.get("climate.hallway")
assert state.state == STATE_UNAVAILABLE
mock_data.reset_mock()
mock_data.return_value = get_data monkeypatch.setattr(get_data[0].parsed["ABC999111"], "hvac_mode", "heat")
mock_data.side_effect = None monkeypatch.setattr(get_data[0].parsed["ABC999111"], "device_on", True)
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
mock_data.assert_called_once()
state = hass.states.get("climate.hallway")
assert state.state == "heat"
mock_data.reset_mock()
mock_data.side_effect = AuthenticationError("info") mock_data.return_value = get_data[0]
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=7)) mock_data.side_effect = None
await hass.async_block_till_done() freezer.tick(timedelta(minutes=1))
mock_data.assert_called_once() async_fire_time_changed(hass)
state = hass.states.get("climate.hallway") await hass.async_block_till_done()
assert state.state == STATE_UNAVAILABLE mock_data.assert_called_once()
state = hass.states.get("climate.hallway")
assert state.state == HVACMode.HEAT
mock_data.reset_mock()
mock_data.side_effect = AuthenticationError("info")
freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
mock_data.assert_called_once()
state = hass.states.get("climate.hallway")
assert state.state == STATE_UNAVAILABLE

View File

@ -2,10 +2,10 @@
from __future__ import annotations from __future__ import annotations
from unittest.mock import patch from unittest.mock import MagicMock
from pysensibo.model import SensiboData
import pytest import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.climate import ( from homeassistant.components.climate import (
ATTR_FAN_MODE, ATTR_FAN_MODE,
@ -17,35 +17,24 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers import device_registry as dr
async def test_entity( async def test_device(
hass: HomeAssistant, hass: HomeAssistant,
device_registry: dr.DeviceRegistry, device_registry: dr.DeviceRegistry,
entity_registry: er.EntityRegistry,
load_int: ConfigEntry, load_int: ConfigEntry,
get_data: SensiboData, snapshot: SnapshotAssertion,
) -> None: ) -> None:
"""Test the Sensibo climate.""" """Test the Sensibo device."""
state1 = hass.states.get("climate.hallway") state1 = hass.states.get("climate.hallway")
assert state1 assert state1
dr_entries = dr.async_entries_for_config_entry(device_registry, load_int.entry_id) assert (
dr_entry: dr.DeviceEntry dr.async_entries_for_config_entry(device_registry, load_int.entry_id)
for dr_entry in dr_entries: == snapshot
if dr_entry.name == "Hallway":
assert dr_entry.identifiers == {("sensibo", "ABC999111")}
device_id = dr_entry.id
er_entries = er.async_entries_for_device(
entity_registry, device_id, include_disabled_entities=True
) )
er_entry: er.RegistryEntry
for er_entry in er_entries:
if er_entry.name == "Hallway":
assert er_entry.unique_id == "Hallway"
@pytest.mark.parametrize("p_error", SENSIBO_ERRORS) @pytest.mark.parametrize("p_error", SENSIBO_ERRORS)
@ -53,35 +42,30 @@ async def test_entity_failed_service_calls(
hass: HomeAssistant, hass: HomeAssistant,
p_error: Exception, p_error: Exception,
load_int: ConfigEntry, load_int: ConfigEntry,
get_data: SensiboData, mock_client: MagicMock,
) -> None: ) -> None:
"""Test the Sensibo send command with error.""" """Test the Sensibo send command with error."""
state = hass.states.get("climate.hallway") state = hass.states.get("climate.hallway")
assert state assert state
with patch( mock_client.async_set_ac_state_property.return_value = {
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property", "result": {"status": "Success"}
return_value={"result": {"status": "Success"}}, }
):
await hass.services.async_call( await hass.services.async_call(
CLIMATE_DOMAIN, CLIMATE_DOMAIN,
SERVICE_SET_FAN_MODE, SERVICE_SET_FAN_MODE,
{ATTR_ENTITY_ID: state.entity_id, ATTR_FAN_MODE: "low"}, {ATTR_ENTITY_ID: state.entity_id, ATTR_FAN_MODE: "low"},
blocking=True, blocking=True,
) )
await hass.async_block_till_done()
state = hass.states.get("climate.hallway") state = hass.states.get("climate.hallway")
assert state.attributes["fan_mode"] == "low" assert state.attributes["fan_mode"] == "low"
with ( mock_client.async_set_ac_state_property.side_effect = p_error
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property", with pytest.raises(HomeAssistantError):
side_effect=p_error,
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call( await hass.services.async_call(
CLIMATE_DOMAIN, CLIMATE_DOMAIN,
SERVICE_SET_FAN_MODE, SERVICE_SET_FAN_MODE,

View File

@ -1,10 +1,8 @@
"""Test for Sensibo component Init.""" """Test for Sensibo integration setup."""
from __future__ import annotations from __future__ import annotations
from unittest.mock import patch from unittest.mock import MagicMock, patch
from pysensibo.model import SensiboData
from homeassistant.components.sensibo.const import DOMAIN from homeassistant.components.sensibo.const import DOMAIN
from homeassistant.components.sensibo.util import NoUsernameError from homeassistant.components.sensibo.util import NoUsernameError
@ -19,137 +17,70 @@ from tests.common import MockConfigEntry
from tests.typing import WebSocketGenerator from tests.typing import WebSocketGenerator
async def test_setup_entry(hass: HomeAssistant, get_data: SensiboData) -> None: async def test_load_unload_entry(hass: HomeAssistant, mock_client: MagicMock) -> None:
"""Test setup entry.""" """Test setup and unload config entry."""
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
source=SOURCE_USER,
data=ENTRY_CONFIG, data=ENTRY_CONFIG,
entry_id="1", entry_id="1",
unique_id="12", unique_id="firstnamelastname",
version=2, version=2,
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
with ( await hass.config_entries.async_setup(entry.entry_id)
patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=get_data,
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]},
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
assert entry.state is ConfigEntryState.LOADED assert entry.state is ConfigEntryState.LOADED
assert await hass.config_entries.async_unload(entry.entry_id)
await hass.async_block_till_done()
async def test_migrate_entry(hass: HomeAssistant, get_data: SensiboData) -> None: assert entry.state is ConfigEntryState.NOT_LOADED
async def test_migrate_entry(hass: HomeAssistant, mock_client: MagicMock) -> None:
"""Test migrate entry unique id.""" """Test migrate entry unique id."""
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
source=SOURCE_USER, source=SOURCE_USER,
data=ENTRY_CONFIG, data=ENTRY_CONFIG,
entry_id="1", entry_id="1",
unique_id="12", unique_id="someother",
version=1, version=1,
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
with ( await hass.config_entries.async_setup(entry.entry_id)
patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=get_data,
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]},
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
assert entry.state is ConfigEntryState.LOADED assert entry.state is ConfigEntryState.LOADED
assert entry.version == 2 assert entry.version == 2
assert entry.unique_id == "username" assert entry.unique_id == "firstnamelastname"
async def test_migrate_entry_fails(hass: HomeAssistant, get_data: SensiboData) -> None: async def test_migrate_entry_fails(hass: HomeAssistant, mock_client: MagicMock) -> None:
"""Test migrate entry unique id.""" """Test migrate entry fails."""
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
source=SOURCE_USER, source=SOURCE_USER,
data=ENTRY_CONFIG, data=ENTRY_CONFIG,
entry_id="1", entry_id="1",
unique_id="12", unique_id="someother",
version=1, version=1,
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
with ( with patch(
patch( "homeassistant.components.sensibo.util.SensiboClient.async_get_me",
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", side_effect=NoUsernameError("No username returned"),
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
side_effect=NoUsernameError("No username returned"),
),
): ):
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
assert entry.state is ConfigEntryState.MIGRATION_ERROR assert entry.state is ConfigEntryState.MIGRATION_ERROR
assert entry.version == 1 assert entry.version == 1
assert entry.unique_id == "12" assert entry.unique_id == "someother"
async def test_unload_entry(hass: HomeAssistant, get_data: SensiboData) -> None:
"""Test unload an entry."""
entry = MockConfigEntry(
domain=DOMAIN,
source=SOURCE_USER,
data=ENTRY_CONFIG,
entry_id="1",
unique_id="12",
version="2",
)
entry.add_to_hass(hass)
with (
patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=get_data,
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]},
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.state is ConfigEntryState.LOADED
assert await hass.config_entries.async_unload(entry.entry_id)
await hass.async_block_till_done()
assert entry.state is ConfigEntryState.NOT_LOADED
async def test_device_remove_devices( async def test_device_remove_devices(

View File

@ -3,8 +3,10 @@
from __future__ import annotations from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from unittest.mock import patch from typing import Any
from unittest.mock import MagicMock
from freezegun.api import FrozenDateTimeFactory
from pysensibo.model import SensiboData from pysensibo.model import SensiboData
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
@ -19,7 +21,6 @@ from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.util import dt as dt_util
from tests.common import async_fire_time_changed, snapshot_platform from tests.common import async_fire_time_changed, snapshot_platform
@ -33,80 +34,55 @@ async def test_number(
hass: HomeAssistant, hass: HomeAssistant,
load_int: ConfigEntry, load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
get_data: SensiboData, get_data: tuple[SensiboData, dict[str, Any]],
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test the Sensibo number.""" """Test the Sensibo number."""
await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id) await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id)
monkeypatch.setattr(get_data.parsed["ABC999111"], "calibration_temp", 0.2) monkeypatch.setattr(get_data[0].parsed["ABC999111"], "calibration_temp", 0.2)
with patch( freezer.tick(timedelta(minutes=5))
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", async_fire_time_changed(hass)
return_value=get_data, await hass.async_block_till_done()
):
async_fire_time_changed(
hass,
dt_util.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("number.hallway_temperature_calibration") state = hass.states.get("number.hallway_temperature_calibration")
assert state1.state == "0.2" assert state.state == "0.2"
@pytest.mark.usefixtures("entity_registry_enabled_by_default") @pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_number_set_value( async def test_number_set_value(
hass: HomeAssistant, hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock
load_int: ConfigEntry,
get_data: SensiboData,
) -> None: ) -> None:
"""Test the Sensibo number service.""" """Test the Sensibo number service."""
state1 = hass.states.get("number.hallway_temperature_calibration") state = hass.states.get("number.hallway_temperature_calibration")
assert state1.state == "0.1" assert state.state == "0.1"
with ( mock_client.async_set_calibration.return_value = {"status": "failure"}
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data",
return_value=get_data,
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_calibration",
return_value={"status": "failure"},
),
):
with pytest.raises(HomeAssistantError):
await hass.services.async_call(
NUMBER_DOMAIN,
SERVICE_SET_VALUE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_VALUE: "0.2"},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("number.hallway_temperature_calibration") with pytest.raises(HomeAssistantError):
assert state2.state == "0.1"
with (
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data",
return_value=get_data,
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_calibration",
return_value={"status": "success"},
),
):
await hass.services.async_call( await hass.services.async_call(
NUMBER_DOMAIN, NUMBER_DOMAIN,
SERVICE_SET_VALUE, SERVICE_SET_VALUE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_VALUE: "0.2"}, {ATTR_ENTITY_ID: state.entity_id, ATTR_VALUE: "0.2"},
blocking=True, blocking=True,
) )
await hass.async_block_till_done()
state2 = hass.states.get("number.hallway_temperature_calibration") state = hass.states.get("number.hallway_temperature_calibration")
assert state2.state == "0.2" assert state.state == "0.1"
mock_client.async_set_calibration.return_value = {"status": "success"}
await hass.services.async_call(
NUMBER_DOMAIN,
SERVICE_SET_VALUE,
{ATTR_ENTITY_ID: state.entity_id, ATTR_VALUE: "0.2"},
blocking=True,
)
state = hass.states.get("number.hallway_temperature_calibration")
assert state.state == "0.2"

View File

@ -3,8 +3,10 @@
from __future__ import annotations from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from unittest.mock import patch from typing import Any
from unittest.mock import MagicMock
from freezegun.api import FrozenDateTimeFactory
from pysensibo.model import SensiboData from pysensibo.model import SensiboData
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
@ -19,7 +21,6 @@ from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.util import dt as dt_util
from tests.common import async_fire_time_changed, snapshot_platform from tests.common import async_fire_time_changed, snapshot_platform
@ -32,42 +33,39 @@ async def test_select(
hass: HomeAssistant, hass: HomeAssistant,
load_int: ConfigEntry, load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
get_data: SensiboData, get_data: tuple[SensiboData, dict[str, Any]],
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test the Sensibo select.""" """Test the Sensibo select."""
await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id) await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id)
monkeypatch.setattr( monkeypatch.setattr(
get_data.parsed["ABC999111"], "horizontal_swing_mode", "fixedleft" get_data[0].parsed["ABC999111"], "horizontal_swing_mode", "fixedleft"
) )
with patch( freezer.tick(timedelta(minutes=5))
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", async_fire_time_changed(hass)
return_value=get_data, await hass.async_block_till_done()
):
async_fire_time_changed(
hass,
dt_util.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("select.hallway_horizontal_swing") state = hass.states.get("select.hallway_horizontal_swing")
assert state1.state == "fixedleft" assert state.state == "fixedleft"
async def test_select_set_option( async def test_select_set_option(
hass: HomeAssistant, hass: HomeAssistant,
load_int: ConfigEntry, load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
get_data: SensiboData, mock_client: MagicMock,
get_data: tuple[SensiboData, dict[str, Any]],
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test the Sensibo select service.""" """Test the Sensibo select service."""
monkeypatch.setattr( monkeypatch.setattr(
get_data.parsed["ABC999111"], get_data[0].parsed["ABC999111"],
"active_features", "active_features",
[ [
"timestamp", "timestamp",
@ -78,45 +76,32 @@ async def test_select_set_option(
], ],
) )
with patch( freezer.tick(timedelta(minutes=5))
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", async_fire_time_changed(hass)
return_value=get_data, await hass.async_block_till_done()
):
async_fire_time_changed(
hass,
dt_util.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("select.hallway_horizontal_swing") state = hass.states.get("select.hallway_horizontal_swing")
assert state1.state == "stopped" assert state.state == "stopped"
with ( mock_client.async_set_ac_state_property.return_value = {
patch( "result": {"status": "failed"}
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", }
return_value=get_data,
), with pytest.raises(
patch( HomeAssistantError,
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "failed"}},
),
pytest.raises(
HomeAssistantError,
),
): ):
await hass.services.async_call( await hass.services.async_call(
SELECT_DOMAIN, SELECT_DOMAIN,
SERVICE_SELECT_OPTION, SERVICE_SELECT_OPTION,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_OPTION: "fixedleft"}, {ATTR_ENTITY_ID: state.entity_id, ATTR_OPTION: "fixedleft"},
blocking=True, blocking=True,
) )
await hass.async_block_till_done()
state2 = hass.states.get("select.hallway_horizontal_swing") state = hass.states.get("select.hallway_horizontal_swing")
assert state2.state == "stopped" assert state.state == "stopped"
monkeypatch.setattr( monkeypatch.setattr(
get_data.parsed["ABC999111"], get_data[0].parsed["ABC999111"],
"active_features", "active_features",
[ [
"timestamp", "timestamp",
@ -128,58 +113,37 @@ async def test_select_set_option(
], ],
) )
with patch( freezer.tick(timedelta(minutes=5))
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", async_fire_time_changed(hass)
return_value=get_data, await hass.async_block_till_done()
):
async_fire_time_changed(
hass,
dt_util.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
with ( mock_client.async_set_ac_state_property.return_value = {
patch( "result": {"status": "Failed", "failureReason": "No connection"}
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", }
),
patch( with pytest.raises(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property", HomeAssistantError,
return_value={
"result": {"status": "Failed", "failureReason": "No connection"}
},
),
pytest.raises(
HomeAssistantError,
),
): ):
await hass.services.async_call( await hass.services.async_call(
SELECT_DOMAIN, SELECT_DOMAIN,
SERVICE_SELECT_OPTION, SERVICE_SELECT_OPTION,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_OPTION: "fixedleft"}, {ATTR_ENTITY_ID: state.entity_id, ATTR_OPTION: "fixedleft"},
blocking=True, blocking=True,
) )
await hass.async_block_till_done()
state2 = hass.states.get("select.hallway_horizontal_swing") state = hass.states.get("select.hallway_horizontal_swing")
assert state2.state == "stopped" assert state.state == "stopped"
with ( mock_client.async_set_ac_state_property.return_value = {
patch( "result": {"status": "Success"}
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", }
return_value=get_data,
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
),
):
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_OPTION: "fixedleft"},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("select.hallway_horizontal_swing") await hass.services.async_call(
assert state2.state == "fixedleft" SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{ATTR_ENTITY_ID: state.entity_id, ATTR_OPTION: "fixedleft"},
blocking=True,
)
state = hass.states.get("select.hallway_horizontal_swing")
assert state.state == "fixedleft"

View File

@ -1,9 +1,9 @@
"""The test for the sensibo select platform.""" """The test for the sensibo sensor platform."""
from __future__ import annotations from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from unittest.mock import patch from typing import Any
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
from pysensibo.model import PureAQI, SensiboData from pysensibo.model import PureAQI, SensiboData
@ -14,7 +14,6 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.util import dt as dt_util
from tests.common import async_fire_time_changed, snapshot_platform from tests.common import async_fire_time_changed, snapshot_platform
@ -28,7 +27,7 @@ async def test_sensor(
hass: HomeAssistant, hass: HomeAssistant,
load_int: ConfigEntry, load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
get_data: SensiboData, get_data: tuple[SensiboData, dict[str, Any]],
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
freezer: FrozenDateTimeFactory, freezer: FrozenDateTimeFactory,
@ -37,17 +36,11 @@ async def test_sensor(
await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id) await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id)
monkeypatch.setattr(get_data.parsed["AAZZAAZZ"], "pm25_pure", PureAQI(2)) monkeypatch.setattr(get_data[0].parsed["AAZZAAZZ"], "pm25_pure", PureAQI(2))
with patch( freezer.tick(timedelta(minutes=5))
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", async_fire_time_changed(hass)
return_value=get_data, await hass.async_block_till_done()
):
async_fire_time_changed(
hass,
dt_util.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("sensor.kitchen_pure_aqi") state = hass.states.get("sensor.kitchen_pure_aqi")
assert state1.state == "moderate" assert state.state == "moderate"

View File

@ -3,8 +3,10 @@
from __future__ import annotations from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from unittest.mock import patch from typing import Any
from unittest.mock import MagicMock
from freezegun.api import FrozenDateTimeFactory
from pysensibo.model import SensiboData from pysensibo.model import SensiboData
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
@ -22,7 +24,6 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.util import dt as dt_util
from tests.common import async_fire_time_changed, snapshot_platform from tests.common import async_fire_time_changed, snapshot_platform
@ -46,220 +47,154 @@ async def test_switch_timer(
hass: HomeAssistant, hass: HomeAssistant,
load_int: ConfigEntry, load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
get_data: SensiboData, mock_client: MagicMock,
get_data: tuple[SensiboData, dict[str, Any]],
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test the Sensibo switch.""" """Test the Sensibo switch timer."""
state1 = hass.states.get("switch.hallway_timer") state = hass.states.get("switch.hallway_timer")
assert state1.state == STATE_OFF assert state.state == STATE_OFF
assert state1.attributes["id"] is None assert state.attributes["id"] is None
assert state1.attributes["turn_on"] is None assert state.attributes["turn_on"] is None
with ( mock_client.async_set_timer.return_value = {
patch( "status": "success",
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", "result": {"id": "SzTGE4oZ4D"},
return_value=get_data, }
),
patch( await hass.services.async_call(
"homeassistant.components.sensibo.util.SensiboClient.async_set_timer", SWITCH_DOMAIN,
return_value={"status": "success", "result": {"id": "SzTGE4oZ4D"}}, SERVICE_TURN_ON,
), {
): ATTR_ENTITY_ID: state.entity_id,
await hass.services.async_call( },
SWITCH_DOMAIN, blocking=True,
SERVICE_TURN_ON, )
{
ATTR_ENTITY_ID: state1.entity_id, monkeypatch.setattr(get_data[0].parsed["ABC999111"], "timer_on", True)
}, monkeypatch.setattr(get_data[0].parsed["ABC999111"], "timer_id", "SzTGE4oZ4D")
blocking=True, monkeypatch.setattr(get_data[0].parsed["ABC999111"], "timer_state_on", False)
)
freezer.tick(timedelta(minutes=5))
async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done()
monkeypatch.setattr(get_data.parsed["ABC999111"], "timer_on", True) state = hass.states.get("switch.hallway_timer")
monkeypatch.setattr(get_data.parsed["ABC999111"], "timer_id", "SzTGE4oZ4D") assert state.state == STATE_ON
monkeypatch.setattr(get_data.parsed["ABC999111"], "timer_state_on", False) assert state.attributes["id"] == "SzTGE4oZ4D"
with patch( assert state.attributes["turn_on"] is False
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=get_data,
):
async_fire_time_changed(
hass,
dt_util.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("switch.hallway_timer")
assert state1.state == STATE_ON
assert state1.attributes["id"] == "SzTGE4oZ4D"
assert state1.attributes["turn_on"] is False
with ( mock_client.async_del_timer.return_value = {
patch( "status": "success",
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", "result": {"id": "SzTGE4oZ4D"},
return_value=get_data, }
),
patch( await hass.services.async_call(
"homeassistant.components.sensibo.util.SensiboClient.async_del_timer", SWITCH_DOMAIN,
return_value={"status": "success", "result": {"id": "SzTGE4oZ4D"}}, SERVICE_TURN_OFF,
), {
): ATTR_ENTITY_ID: state.entity_id,
await hass.services.async_call( },
SWITCH_DOMAIN, blocking=True,
SERVICE_TURN_OFF, )
{
ATTR_ENTITY_ID: state1.entity_id, monkeypatch.setattr(get_data[0].parsed["ABC999111"], "timer_on", False)
},
blocking=True, freezer.tick(timedelta(minutes=5))
) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done()
monkeypatch.setattr(get_data.parsed["ABC999111"], "timer_on", False) state = hass.states.get("switch.hallway_timer")
assert state.state == STATE_OFF
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=get_data,
):
async_fire_time_changed(
hass,
dt_util.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("switch.hallway_timer")
assert state1.state == STATE_OFF
async def test_switch_pure_boost( async def test_switch_pure_boost(
hass: HomeAssistant, hass: HomeAssistant,
load_int: ConfigEntry, load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
get_data: SensiboData, mock_client: MagicMock,
get_data: tuple[SensiboData, dict[str, Any]],
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test the Sensibo switch.""" """Test the Sensibo switch pure boost."""
state1 = hass.states.get("switch.kitchen_pure_boost") state = hass.states.get("switch.kitchen_pure_boost")
assert state1.state == STATE_OFF assert state.state == STATE_OFF
with ( mock_client.async_set_pureboost.return_value = {"status": "success"}
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", await hass.services.async_call(
return_value=get_data, SWITCH_DOMAIN,
), SERVICE_TURN_ON,
patch( {
"homeassistant.components.sensibo.util.SensiboClient.async_set_pureboost", ATTR_ENTITY_ID: state.entity_id,
return_value={"status": "success"}, },
), blocking=True,
): )
await hass.services.async_call(
SWITCH_DOMAIN, monkeypatch.setattr(get_data[0].parsed["AAZZAAZZ"], "pure_boost_enabled", True)
SERVICE_TURN_ON, monkeypatch.setattr(
{ get_data[0].parsed["AAZZAAZZ"], "pure_measure_integration", None
ATTR_ENTITY_ID: state1.entity_id, )
},
blocking=True, freezer.tick(timedelta(minutes=5))
) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done()
monkeypatch.setattr(get_data.parsed["AAZZAAZZ"], "pure_boost_enabled", True) state = hass.states.get("switch.kitchen_pure_boost")
monkeypatch.setattr(get_data.parsed["AAZZAAZZ"], "pure_measure_integration", None) assert state.state == STATE_ON
with patch( await hass.services.async_call(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", SWITCH_DOMAIN,
return_value=get_data, SERVICE_TURN_OFF,
): {
async_fire_time_changed( ATTR_ENTITY_ID: state.entity_id,
hass, },
dt_util.utcnow() + timedelta(minutes=5), blocking=True,
) )
await hass.async_block_till_done()
state1 = hass.states.get("switch.kitchen_pure_boost")
assert state1.state == STATE_ON
with ( monkeypatch.setattr(get_data[0].parsed["AAZZAAZZ"], "pure_boost_enabled", False)
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", freezer.tick(timedelta(minutes=5))
return_value=get_data, async_fire_time_changed(hass)
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_pureboost",
return_value={"status": "success"},
),
):
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_OFF,
{
ATTR_ENTITY_ID: state1.entity_id,
},
blocking=True,
)
await hass.async_block_till_done() await hass.async_block_till_done()
monkeypatch.setattr(get_data.parsed["AAZZAAZZ"], "pure_boost_enabled", False) state = hass.states.get("switch.kitchen_pure_boost")
assert state.state == STATE_OFF
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=get_data,
):
async_fire_time_changed(
hass,
dt_util.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("switch.kitchen_pure_boost")
assert state1.state == STATE_OFF
async def test_switch_command_failure( async def test_switch_command_failure(
hass: HomeAssistant, hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock
load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch,
get_data: SensiboData,
) -> None: ) -> None:
"""Test the Sensibo switch fails commands.""" """Test the Sensibo switch fails commands."""
state1 = hass.states.get("switch.hallway_timer") state = hass.states.get("switch.hallway_timer")
with ( mock_client.async_set_timer.return_value = {"status": "failure"}
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", with pytest.raises(
return_value=get_data, HomeAssistantError,
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_timer",
return_value={"status": "failure"},
),
pytest.raises(
HomeAssistantError,
),
): ):
await hass.services.async_call( await hass.services.async_call(
SWITCH_DOMAIN, SWITCH_DOMAIN,
SERVICE_TURN_ON, SERVICE_TURN_ON,
{ {
ATTR_ENTITY_ID: state1.entity_id, ATTR_ENTITY_ID: state.entity_id,
}, },
blocking=True, blocking=True,
) )
with ( mock_client.async_del_timer.return_value = {"status": "failure"}
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", with pytest.raises(
return_value=get_data, HomeAssistantError,
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_del_timer",
return_value={"status": "failure"},
),
pytest.raises(
HomeAssistantError,
),
): ):
await hass.services.async_call( await hass.services.async_call(
SWITCH_DOMAIN, SWITCH_DOMAIN,
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
{ {
ATTR_ENTITY_ID: state1.entity_id, ATTR_ENTITY_ID: state.entity_id,
}, },
blocking=True, blocking=True,
) )
@ -269,113 +204,78 @@ async def test_switch_climate_react(
hass: HomeAssistant, hass: HomeAssistant,
load_int: ConfigEntry, load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
get_data: SensiboData, mock_client: MagicMock,
get_data: tuple[SensiboData, dict[str, Any]],
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test the Sensibo switch for climate react.""" """Test the Sensibo switch for climate react."""
state1 = hass.states.get("switch.hallway_climate_react") state = hass.states.get("switch.hallway_climate_react")
assert state1.state == STATE_OFF assert state.state == STATE_OFF
with ( mock_client.async_enable_climate_react.return_value = {"status": "success"}
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", await hass.services.async_call(
return_value=get_data, SWITCH_DOMAIN,
), SERVICE_TURN_ON,
patch( {
"homeassistant.components.sensibo.util.SensiboClient.async_enable_climate_react", ATTR_ENTITY_ID: state.entity_id,
return_value={"status": "success"}, },
), blocking=True,
): )
await hass.services.async_call(
SWITCH_DOMAIN, monkeypatch.setattr(get_data[0].parsed["ABC999111"], "smart_on", True)
SERVICE_TURN_ON,
{ freezer.tick(timedelta(minutes=5))
ATTR_ENTITY_ID: state1.entity_id, async_fire_time_changed(hass)
},
blocking=True,
)
await hass.async_block_till_done() await hass.async_block_till_done()
monkeypatch.setattr(get_data.parsed["ABC999111"], "smart_on", True) state = hass.states.get("switch.hallway_climate_react")
assert state.state == STATE_ON
with patch( await hass.services.async_call(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", SWITCH_DOMAIN,
return_value=get_data, SERVICE_TURN_OFF,
): {
async_fire_time_changed( ATTR_ENTITY_ID: state.entity_id,
hass, },
dt_util.utcnow() + timedelta(minutes=5), blocking=True,
) )
await hass.async_block_till_done()
state1 = hass.states.get("switch.hallway_climate_react")
assert state1.state == STATE_ON
with ( monkeypatch.setattr(get_data[0].parsed["ABC999111"], "smart_on", False)
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", freezer.tick(timedelta(minutes=5))
return_value=get_data, async_fire_time_changed(hass)
),
patch(
"homeassistant.components.sensibo.util.SensiboClient.async_enable_climate_react",
return_value={"status": "success"},
),
):
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_OFF,
{
ATTR_ENTITY_ID: state1.entity_id,
},
blocking=True,
)
await hass.async_block_till_done() await hass.async_block_till_done()
monkeypatch.setattr(get_data.parsed["ABC999111"], "smart_on", False) state = hass.states.get("switch.hallway_climate_react")
assert state.state == STATE_OFF
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=get_data,
):
async_fire_time_changed(
hass,
dt_util.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("switch.hallway_climate_react")
assert state1.state == STATE_OFF
async def test_switch_climate_react_no_data( async def test_switch_climate_react_no_data(
hass: HomeAssistant, hass: HomeAssistant,
load_int: ConfigEntry, load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
get_data: SensiboData, get_data: tuple[SensiboData, dict[str, Any]],
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test the Sensibo switch for climate react.""" """Test the Sensibo switch for climate react with no data."""
monkeypatch.setattr(get_data.parsed["ABC999111"], "smart_type", None) monkeypatch.setattr(get_data[0].parsed["ABC999111"], "smart_type", None)
with patch( freezer.tick(timedelta(minutes=5))
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", async_fire_time_changed(hass)
return_value=get_data, await hass.async_block_till_done()
):
async_fire_time_changed(
hass,
dt_util.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("switch.hallway_climate_react") state = hass.states.get("switch.hallway_climate_react")
assert state1.state == STATE_OFF assert state.state == STATE_OFF
with pytest.raises(HomeAssistantError): with pytest.raises(HomeAssistantError):
await hass.services.async_call( await hass.services.async_call(
SWITCH_DOMAIN, SWITCH_DOMAIN,
SERVICE_TURN_ON, SERVICE_TURN_ON,
{ {
ATTR_ENTITY_ID: state1.entity_id, ATTR_ENTITY_ID: state.entity_id,
}, },
blocking=True, blocking=True,
) )
await hass.async_block_till_done()

View File

@ -3,7 +3,7 @@
from __future__ import annotations from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from unittest.mock import patch from typing import Any
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
from pysensibo.model import SensiboData from pysensibo.model import SensiboData
@ -27,7 +27,7 @@ async def test_update(
hass: HomeAssistant, hass: HomeAssistant,
load_int: ConfigEntry, load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
get_data: SensiboData, get_data: tuple[SensiboData, dict[str, Any]],
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
freezer: FrozenDateTimeFactory, freezer: FrozenDateTimeFactory,
@ -36,15 +36,11 @@ async def test_update(
await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id) await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id)
monkeypatch.setattr(get_data.parsed["ABC999111"], "fw_ver", "SKY30048") monkeypatch.setattr(get_data[0].parsed["ABC999111"], "fw_ver", "SKY30048")
with patch( freezer.tick(timedelta(minutes=5))
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", async_fire_time_changed(hass)
return_value=get_data, await hass.async_block_till_done()
):
freezer.tick(timedelta(minutes=5))
async_fire_time_changed(hass)
await hass.async_block_till_done()
state1 = hass.states.get("update.hallway_firmware") state = hass.states.get("update.hallway_firmware")
assert state1.state == STATE_OFF assert state.state == STATE_OFF