Add basic test support to Homematic IP Cloud (#27228)
* Add basic test support to Homematic IP Cloud * move test data address comments
This commit is contained in:
parent
2c6a869bc6
commit
476f24e451
9 changed files with 5672 additions and 10 deletions
|
@ -115,6 +115,7 @@ class HomematicipAccesspointStatus(HomematicipGenericDevice):
|
|||
|
||||
def __init__(self, home: AsyncHome) -> None:
|
||||
"""Initialize access point device."""
|
||||
home.modelType = "HmIP-HAP"
|
||||
super().__init__(home, home)
|
||||
|
||||
@property
|
||||
|
|
75
tests/components/homematicip_cloud/conftest.py
Normal file
75
tests/components/homematicip_cloud/conftest.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
"""Initializer helpers for HomematicIP fake server."""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from homematicip.aio.connection import AsyncConnection
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.homematicip_cloud import (
|
||||
DOMAIN as HMIPC_DOMAIN,
|
||||
const as hmipc,
|
||||
hap as hmip_hap,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .helper import AUTH_TOKEN, HAPID, HomeTemplate
|
||||
|
||||
from tests.common import MockConfigEntry, mock_coro
|
||||
|
||||
|
||||
@pytest.fixture(name="mock_connection")
|
||||
def mock_connection_fixture():
|
||||
"""Return a mockked connection."""
|
||||
connection = MagicMock(spec=AsyncConnection)
|
||||
|
||||
def _rest_call_side_effect(path, body=None):
|
||||
return path, body
|
||||
|
||||
connection._restCall.side_effect = _rest_call_side_effect # pylint: disable=W0212
|
||||
connection.api_call.return_value = mock_coro(True)
|
||||
|
||||
return connection
|
||||
|
||||
|
||||
@pytest.fixture(name="default_mock_home")
|
||||
def default_mock_home_fixture(mock_connection):
|
||||
"""Create a fake homematic async home."""
|
||||
return HomeTemplate(connection=mock_connection).init_home().get_async_home_mock()
|
||||
|
||||
|
||||
@pytest.fixture(name="hmip_config_entry")
|
||||
def hmip_config_entry_fixture():
|
||||
"""Create a fake config entriy for homematic ip cloud."""
|
||||
entry_data = {
|
||||
hmipc.HMIPC_HAPID: HAPID,
|
||||
hmipc.HMIPC_AUTHTOKEN: AUTH_TOKEN,
|
||||
hmipc.HMIPC_NAME: "",
|
||||
}
|
||||
config_entry = MockConfigEntry(
|
||||
version=1,
|
||||
domain=HMIPC_DOMAIN,
|
||||
title=HAPID,
|
||||
data=entry_data,
|
||||
source="import",
|
||||
connection_class=config_entries.CONN_CLASS_CLOUD_PUSH,
|
||||
system_options={"disable_new_entities": False},
|
||||
)
|
||||
|
||||
return config_entry
|
||||
|
||||
|
||||
@pytest.fixture(name="default_mock_hap")
|
||||
async def default_mock_hap_fixture(
|
||||
hass: HomeAssistant, default_mock_home, hmip_config_entry
|
||||
):
|
||||
"""Create a fake homematic access point."""
|
||||
hass.config.components.add(HMIPC_DOMAIN)
|
||||
hap = hmip_hap.HomematicipHAP(hass, hmip_config_entry)
|
||||
with patch.object(hap, "get_hap", return_value=mock_coro(default_mock_home)):
|
||||
assert await hap.async_setup() is True
|
||||
|
||||
hass.data[HMIPC_DOMAIN] = {HAPID: hap}
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
return hap
|
128
tests/components/homematicip_cloud/helper.py
Normal file
128
tests/components/homematicip_cloud/helper.py
Normal file
|
@ -0,0 +1,128 @@
|
|||
"""Helper for HomematicIP Cloud Tests."""
|
||||
import json
|
||||
from unittest.mock import Mock
|
||||
|
||||
from homematicip.aio.class_maps import (
|
||||
TYPE_CLASS_MAP,
|
||||
TYPE_GROUP_MAP,
|
||||
TYPE_SECURITY_EVENT_MAP,
|
||||
)
|
||||
from homematicip.aio.home import AsyncHome
|
||||
from homematicip.home import Home
|
||||
|
||||
from tests.common import load_fixture
|
||||
|
||||
HAPID = "Mock_HAP"
|
||||
AUTH_TOKEN = "1234"
|
||||
HOME_JSON = "homematicip_cloud.json"
|
||||
|
||||
|
||||
def get_and_check_entity_basics(
|
||||
hass, default_mock_hap, entity_id, entity_name, device_model
|
||||
):
|
||||
"""Get and test basic device."""
|
||||
ha_entity = hass.states.get(entity_id)
|
||||
assert ha_entity is not None
|
||||
assert ha_entity.attributes["model_type"] == device_model
|
||||
assert ha_entity.name == entity_name
|
||||
|
||||
hmip_device = default_mock_hap.home.template.search_mock_device_by_id(
|
||||
ha_entity.attributes["id"]
|
||||
)
|
||||
assert hmip_device is not None
|
||||
return ha_entity, hmip_device
|
||||
|
||||
|
||||
async def async_manipulate_test_data(
|
||||
hass, hmip_device, attribute, new_value, channel=1
|
||||
):
|
||||
"""Set new value on hmip device."""
|
||||
if channel == 1:
|
||||
setattr(hmip_device, attribute, new_value)
|
||||
functional_channel = hmip_device.functionalChannels[channel]
|
||||
setattr(functional_channel, attribute, new_value)
|
||||
|
||||
hmip_device.fire_update_event()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
class HomeTemplate(Home):
|
||||
"""
|
||||
Home template as builder for home mock.
|
||||
|
||||
It is based on the upstream libs home class to generate hmip devices
|
||||
and groups based on the given homematicip_cloud.json.
|
||||
|
||||
All further testing activities should be done by using the AsyncHome mock,
|
||||
that is generated by get_async_home_mock(self).
|
||||
|
||||
The class also generated mocks of devices and groups for further testing.
|
||||
"""
|
||||
|
||||
_typeClassMap = TYPE_CLASS_MAP
|
||||
_typeGroupMap = TYPE_GROUP_MAP
|
||||
_typeSecurityEventMap = TYPE_SECURITY_EVENT_MAP
|
||||
|
||||
def __init__(self, connection=None):
|
||||
"""Init template with connection."""
|
||||
super().__init__(connection=connection)
|
||||
self.mock_devices = []
|
||||
self.mock_groups = []
|
||||
|
||||
def init_home(self, json_path=HOME_JSON):
|
||||
"""Init template with json."""
|
||||
json_state = json.loads(load_fixture(HOME_JSON), encoding="UTF-8")
|
||||
self.update_home(json_state=json_state, clearConfig=True)
|
||||
self._generate_mocks()
|
||||
return self
|
||||
|
||||
def _generate_mocks(self):
|
||||
"""Generate mocks for groups and devices."""
|
||||
for device in self.devices:
|
||||
self.mock_devices.append(_get_mock(device))
|
||||
for group in self.groups:
|
||||
self.mock_groups.append(_get_mock(group))
|
||||
|
||||
def search_mock_device_by_id(self, device_id):
|
||||
"""Search a device by given id."""
|
||||
for device in self.mock_devices:
|
||||
if device.id == device_id:
|
||||
return device
|
||||
return None
|
||||
|
||||
def search_mock_group_by_id(self, group_id):
|
||||
"""Search a group by given id."""
|
||||
for group in self.mock_groups:
|
||||
if group.id == group_id:
|
||||
return group
|
||||
return None
|
||||
|
||||
def get_async_home_mock(self):
|
||||
"""
|
||||
Create Mock for Async_Home. based on template to be used for testing.
|
||||
|
||||
It adds collections of mocked devices and groups to the home objects,
|
||||
and sets reuired attributes.
|
||||
"""
|
||||
mock_home = Mock(
|
||||
check_connection=self._connection,
|
||||
id=HAPID,
|
||||
connected=True,
|
||||
dutyCycle=self.dutyCycle,
|
||||
devices=self.mock_devices,
|
||||
groups=self.mock_groups,
|
||||
weather=self.weather,
|
||||
location=self.location,
|
||||
label="home label",
|
||||
template=self,
|
||||
spec=AsyncHome,
|
||||
)
|
||||
mock_home.name = ""
|
||||
return mock_home
|
||||
|
||||
|
||||
def _get_mock(instance):
|
||||
"""Create a mock and copy instance attributes over mock."""
|
||||
mock = Mock(spec=instance, wraps=instance)
|
||||
mock.__dict__.update(instance.__dict__)
|
||||
return mock
|
41
tests/components/homematicip_cloud/test_binary_sensors.py
Normal file
41
tests/components/homematicip_cloud/test_binary_sensors.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
"""Tests for HomematicIP Cloud lights."""
|
||||
import logging
|
||||
|
||||
from tests.components.homematicip_cloud.helper import (
|
||||
async_manipulate_test_data,
|
||||
get_and_check_entity_basics,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def test_hmip_sam(hass, default_mock_hap):
|
||||
"""Test HomematicipLight."""
|
||||
entity_id = "binary_sensor.garagentor"
|
||||
entity_name = "Garagentor"
|
||||
device_model = "HmIP-SAM"
|
||||
|
||||
ha_entity, hmip_device = get_and_check_entity_basics(
|
||||
hass, default_mock_hap, entity_id, entity_name, device_model
|
||||
)
|
||||
|
||||
assert ha_entity.state == "on"
|
||||
assert ha_entity.attributes["acceleration_sensor_mode"] == "FLAT_DECT"
|
||||
assert ha_entity.attributes["acceleration_sensor_neutral_position"] == "VERTICAL"
|
||||
assert ha_entity.attributes["acceleration_sensor_sensitivity"] == "SENSOR_RANGE_4G"
|
||||
assert ha_entity.attributes["acceleration_sensor_trigger_angle"] == 45
|
||||
service_call_counter = len(hmip_device.mock_calls)
|
||||
|
||||
await async_manipulate_test_data(
|
||||
hass, hmip_device, "accelerationSensorTriggered", False
|
||||
)
|
||||
ha_entity = hass.states.get(entity_id)
|
||||
assert ha_entity.state == "off"
|
||||
assert len(hmip_device.mock_calls) == service_call_counter + 1
|
||||
|
||||
await async_manipulate_test_data(
|
||||
hass, hmip_device, "accelerationSensorTriggered", True
|
||||
)
|
||||
ha_entity = hass.states.get(entity_id)
|
||||
assert ha_entity.state == "on"
|
||||
assert len(hmip_device.mock_calls) == service_call_counter + 2
|
|
@ -1,8 +1,7 @@
|
|||
"""Tests for HomematicIP Cloud config flow."""
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.homematicip_cloud import hap as hmipc
|
||||
from homeassistant.components.homematicip_cloud import config_flow, const
|
||||
from homeassistant.components.homematicip_cloud import config_flow, const, hap as hmipc
|
||||
|
||||
from tests.common import MockConfigEntry, mock_coro
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ from unittest.mock import Mock, patch
|
|||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.homematicip_cloud import const, errors, hap as hmipc
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.components.homematicip_cloud import hap as hmipc
|
||||
from homeassistant.components.homematicip_cloud import const, errors
|
||||
|
||||
from tests.common import mock_coro, mock_coro_func
|
||||
|
||||
|
||||
|
@ -94,8 +94,8 @@ async def test_hap_setup_connection_error():
|
|||
), pytest.raises(ConfigEntryNotReady):
|
||||
await hap.async_setup()
|
||||
|
||||
assert len(hass.async_add_job.mock_calls) == 0
|
||||
assert len(hass.config_entries.flow.async_init.mock_calls) == 0
|
||||
assert not hass.async_add_job.mock_calls
|
||||
assert not hass.config_entries.flow.async_init.mock_calls
|
||||
|
||||
|
||||
async def test_hap_reset_unloads_entry_if_setup():
|
||||
|
@ -114,7 +114,7 @@ async def test_hap_reset_unloads_entry_if_setup():
|
|||
assert await hap.async_setup() is True
|
||||
|
||||
assert hap.home is home
|
||||
assert len(hass.services.async_register.mock_calls) == 0
|
||||
assert not hass.services.async_register.mock_calls
|
||||
assert len(hass.config_entries.async_forward_entry_setup.mock_calls) == 8
|
||||
|
||||
hass.config_entries.async_forward_entry_unload.return_value = mock_coro(True)
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.components import homematicip_cloud as hmipc
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import mock_coro, MockConfigEntry
|
||||
from tests.common import MockConfigEntry, mock_coro
|
||||
|
||||
|
||||
async def test_config_with_accesspoint_passed_to_config_entry(hass):
|
||||
|
@ -53,7 +53,7 @@ async def test_config_already_registered_not_passed_to_config_entry(hass):
|
|||
)
|
||||
|
||||
# No flow started
|
||||
assert len(mock_config_entries.flow.mock_calls) == 0
|
||||
assert not mock_config_entries.flow.mock_calls
|
||||
|
||||
|
||||
async def test_setup_entry_successful(hass):
|
||||
|
|
77
tests/components/homematicip_cloud/test_lights.py
Normal file
77
tests/components/homematicip_cloud/test_lights.py
Normal file
|
@ -0,0 +1,77 @@
|
|||
"""Tests for HomematicIP Cloud lights."""
|
||||
import logging
|
||||
|
||||
from tests.components.homematicip_cloud.helper import (
|
||||
async_manipulate_test_data,
|
||||
get_and_check_entity_basics,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def test_hmip_light(hass, default_mock_hap):
|
||||
"""Test HomematicipLight."""
|
||||
entity_id = "light.treppe"
|
||||
entity_name = "Treppe"
|
||||
device_model = "HmIP-BSL"
|
||||
|
||||
ha_entity, hmip_device = get_and_check_entity_basics(
|
||||
hass, default_mock_hap, entity_id, entity_name, device_model
|
||||
)
|
||||
|
||||
assert ha_entity.state == "on"
|
||||
|
||||
service_call_counter = len(hmip_device.mock_calls)
|
||||
await hass.services.async_call(
|
||||
"light", "turn_off", {"entity_id": entity_id}, blocking=True
|
||||
)
|
||||
assert len(hmip_device.mock_calls) == service_call_counter + 1
|
||||
assert hmip_device.mock_calls[-1][0] == "turn_off"
|
||||
await async_manipulate_test_data(hass, hmip_device, "on", False)
|
||||
ha_entity = hass.states.get(entity_id)
|
||||
assert ha_entity.state == "off"
|
||||
|
||||
await hass.services.async_call(
|
||||
"light", "turn_on", {"entity_id": entity_id}, blocking=True
|
||||
)
|
||||
assert len(hmip_device.mock_calls) == service_call_counter + 3
|
||||
assert hmip_device.mock_calls[-1][0] == "turn_on"
|
||||
await async_manipulate_test_data(hass, hmip_device, "on", True)
|
||||
ha_entity = hass.states.get(entity_id)
|
||||
assert ha_entity.state == "on"
|
||||
|
||||
|
||||
# HomematicipLightMeasuring
|
||||
# HomematicipDimmer
|
||||
|
||||
|
||||
async def test_hmip_notification_light(hass, default_mock_hap):
|
||||
"""Test HomematicipNotificationLight."""
|
||||
entity_id = "light.treppe_top_notification"
|
||||
entity_name = "Treppe Top Notification"
|
||||
device_model = "HmIP-BSL"
|
||||
|
||||
ha_entity, hmip_device = get_and_check_entity_basics(
|
||||
hass, default_mock_hap, entity_id, entity_name, device_model
|
||||
)
|
||||
|
||||
assert ha_entity.state == "off"
|
||||
service_call_counter = len(hmip_device.mock_calls)
|
||||
|
||||
await hass.services.async_call(
|
||||
"light", "turn_on", {"entity_id": entity_id}, blocking=True
|
||||
)
|
||||
assert len(hmip_device.mock_calls) == service_call_counter + 1
|
||||
assert hmip_device.mock_calls[-1][0] == "set_rgb_dim_level"
|
||||
await async_manipulate_test_data(hass, hmip_device, "dimLevel", 100, 2)
|
||||
ha_entity = hass.states.get(entity_id)
|
||||
assert ha_entity.state == "on"
|
||||
|
||||
await hass.services.async_call(
|
||||
"light", "turn_off", {"entity_id": entity_id}, blocking=True
|
||||
)
|
||||
assert len(hmip_device.mock_calls) == service_call_counter + 3
|
||||
assert hmip_device.mock_calls[-1][0] == "set_rgb_dim_level"
|
||||
await async_manipulate_test_data(hass, hmip_device, "dimLevel", 0, 2)
|
||||
ha_entity = hass.states.get(entity_id)
|
||||
assert ha_entity.state == "off"
|
5341
tests/fixtures/homematicip_cloud.json
vendored
Normal file
5341
tests/fixtures/homematicip_cloud.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue