Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speed up tests of HomematicIP Cloud #31810

Merged
merged 2 commits into from
Feb 14, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 9 additions & 43 deletions tests/components/homematicip_cloud/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Initializer helpers for HomematicIP fake server."""
from asynctest import CoroutineMock, MagicMock, Mock, patch
from asynctest import CoroutineMock, MagicMock, Mock
from homematicip.aio.auth import AsyncAuth
from homematicip.aio.connection import AsyncConnection
from homematicip.aio.home import AsyncHome
Expand All @@ -19,9 +19,8 @@
from homeassistant.components.homematicip_cloud.hap import HomematicipHAP
from homeassistant.config_entries import SOURCE_IMPORT
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
from homeassistant.setup import async_setup_component

from .helper import AUTH_TOKEN, HAPID, HAPPIN, HomeTemplate
from .helper import AUTH_TOKEN, HAPID, HAPPIN, HomeFactory

from tests.common import MockConfigEntry

Expand Down Expand Up @@ -66,46 +65,12 @@ def hmip_config_entry_fixture() -> config_entries.ConfigEntry:
return config_entry


@pytest.fixture(name="default_mock_home")
def default_mock_home_fixture(mock_connection) -> AsyncHome:
"""Create a fake homematic async home."""
return HomeTemplate(connection=mock_connection).init_home().get_async_home_mock()


@pytest.fixture(name="default_mock_hap")
async def default_mock_hap_fixture(
@pytest.fixture(name="default_mock_hap_factory")
async def default_mock_hap_factory_fixture(
hass: HomeAssistantType, mock_connection, hmip_config_entry
) -> HomematicipHAP:
"""Create a mocked homematic access point."""
return await get_mock_hap(hass, mock_connection, hmip_config_entry)


async def get_mock_hap(
hass: HomeAssistantType,
mock_connection,
hmip_config_entry: config_entries.ConfigEntry,
) -> HomematicipHAP:
"""Create a mocked homematic access point."""
home_name = hmip_config_entry.data["name"]
mock_home = (
HomeTemplate(connection=mock_connection, home_name=home_name)
.init_home()
.get_async_home_mock()
)

hmip_config_entry.add_to_hass(hass)
with patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipHAP.get_hap",
return_value=mock_home,
):
assert await async_setup_component(hass, HMIPC_DOMAIN, {}) is True

await hass.async_block_till_done()

hap = hass.data[HMIPC_DOMAIN][HAPID]
mock_home.on_update(hap.async_update)
mock_home.on_create(hap.async_create_entity)
return hap
return HomeFactory(hass, mock_connection, hmip_config_entry)


@pytest.fixture(name="hmip_config")
Expand All @@ -130,13 +95,14 @@ def dummy_config_fixture() -> ConfigType:

@pytest.fixture(name="mock_hap_with_service")
async def mock_hap_with_service_fixture(
hass: HomeAssistantType, default_mock_hap, dummy_config
hass: HomeAssistantType, default_mock_hap_factory, dummy_config
) -> HomematicipHAP:
"""Create a fake homematic access point with hass services."""
mock_hap = await default_mock_hap_factory.async_get_mock_hap()
await hmip_async_setup(hass, dummy_config)
await hass.async_block_till_done()
hass.data[HMIPC_DOMAIN] = {HAPID: default_mock_hap}
return default_mock_hap
hass.data[HMIPC_DOMAIN] = {HAPID: mock_hap}
return mock_hap


@pytest.fixture(name="simple_mock_home")
Expand Down
81 changes: 74 additions & 7 deletions tests/components/homematicip_cloud/helper.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Helper for HomematicIP Cloud Tests."""
import json

from asynctest import Mock
from asynctest import Mock, patch
from homematicip.aio.class_maps import (
TYPE_CLASS_MAP,
TYPE_GROUP_MAP,
Expand All @@ -12,10 +12,15 @@
from homematicip.aio.home import AsyncHome
from homematicip.home import Home

from homeassistant import config_entries
from homeassistant.components.homematicip_cloud import DOMAIN as HMIPC_DOMAIN
from homeassistant.components.homematicip_cloud.device import (
ATTR_IS_GROUP,
ATTR_MODEL_TYPE,
)
from homeassistant.components.homematicip_cloud.hap import HomematicipHAP
from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.setup import async_setup_component

from tests.common import load_fixture

Expand All @@ -25,17 +30,15 @@
HOME_JSON = "homematicip_cloud.json"


def get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
):
def get_and_check_entity_basics(hass, mock_hap, entity_id, entity_name, device_model):
"""Get and test basic device."""
ha_state = hass.states.get(entity_id)
assert ha_state is not None
if device_model:
assert ha_state.attributes[ATTR_MODEL_TYPE] == device_model
assert ha_state.name == entity_name

hmip_device = default_mock_hap.hmip_device_by_entity_id.get(entity_id)
hmip_device = mock_hap.hmip_device_by_entity_id.get(entity_id)

if hmip_device:
if isinstance(hmip_device, AsyncDevice):
Expand Down Expand Up @@ -67,6 +70,51 @@ async def async_manipulate_test_data(
await hass.async_block_till_done()


class HomeFactory:
"""Factory to create a HomematicIP Cloud Home."""

def __init__(
self,
hass: HomeAssistantType,
mock_connection,
hmip_config_entry: config_entries.ConfigEntry,
):
"""Initialize the Factory."""
self.hass = hass
self.mock_connection = mock_connection
self.hmip_config_entry = hmip_config_entry

async def async_get_mock_hap(
self, test_devices=[], test_groups=[]
) -> HomematicipHAP:
"""Create a mocked homematic access point."""
home_name = self.hmip_config_entry.data["name"]
mock_home = (
HomeTemplate(
connection=self.mock_connection,
home_name=home_name,
test_devices=test_devices,
test_groups=test_groups,
)
.init_home()
.get_async_home_mock()
)

self.hmip_config_entry.add_to_hass(self.hass)
with patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipHAP.get_hap",
return_value=mock_home,
):
assert await async_setup_component(self.hass, HMIPC_DOMAIN, {}) is True

await self.hass.async_block_till_done()

hap = self.hass.data[HMIPC_DOMAIN][HAPID]
mock_home.on_update(hap.async_update)
mock_home.on_create(hap.async_create_entity)
return hap


class HomeTemplate(Home):
"""
Home template as builder for home mock.
Expand All @@ -84,17 +132,36 @@ class HomeTemplate(Home):
_typeGroupMap = TYPE_GROUP_MAP
_typeSecurityEventMap = TYPE_SECURITY_EVENT_MAP

def __init__(self, connection=None, home_name=""):
def __init__(self, connection=None, home_name="", test_devices=[], test_groups=[]):
"""Init template with connection."""
super().__init__(connection=connection)
self.label = "Access Point"
self.name = home_name
self.model_type = "HmIP-HAP"
self.init_json_state = None
self.test_devices = test_devices
self.test_groups = test_groups

def _cleanup_json(self, json):
if self.test_devices is not None:
new_devices = {}
for json_device in json["devices"].items():
if json_device[1]["label"] in self.test_devices:
new_devices.update([json_device])
json["devices"] = new_devices

if self.test_groups is not None:
new_groups = {}
for json_group in json["groups"].items():
if json_group[1]["label"] in self.test_groups:
new_groups.update([json_group])
json["groups"] = new_groups

return json

def init_home(self, json_path=HOME_JSON):
"""Init template with json."""
self.init_json_state = json.loads(load_fixture(HOME_JSON))
self.init_json_state = self._cleanup_json(json.loads(load_fixture(HOME_JSON)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I don't think json_path is ever used in init_home and so it's always the same fixture. I think that it could help in loading the fixture once instead of every test. I would still do json.loads on each test in case the original data is mutated.

# Put on top of file.
FIXTURE_DATA = load_fixture(HOME_JSON)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

self.update_home(json_state=self.init_json_state, clearConfig=True)
return self

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,23 @@ async def test_manually_configured_platform(hass):
assert not hass.data.get(HMIPC_DOMAIN)


async def test_hmip_alarm_control_panel(hass, default_mock_hap):
async def test_hmip_alarm_control_panel(hass, default_mock_hap_factory):
"""Test HomematicipAlarmControlPanel."""
entity_id = "alarm_control_panel.hmip_alarm_control_panel"
entity_name = "HmIP Alarm Control Panel"
device_model = None
mock_hap = await default_mock_hap_factory.async_get_mock_hap(
test_groups=["EXTERNAL", "INTERNAL"]
)

ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
hass, mock_hap, entity_id, entity_name, device_model
)

assert ha_state.state == "disarmed"
assert not hmip_device

home = default_mock_hap.home
home = mock_hap.home

await hass.services.async_call(
"alarm_control_panel", "alarm_arm_away", {"entity_id": entity_id}, blocking=True
Expand Down
Loading