Skip to content

Commit

Permalink
Merge pull request #24836 from home-assistant/rc
Browse files Browse the repository at this point in the history
0.95.3
  • Loading branch information
balloob authored Jun 29, 2019
2 parents 0871d6c + 072879c commit 2e9c71f
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 159 deletions.
12 changes: 11 additions & 1 deletion homeassistant/components/cloud/alexa_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def endpoint(self):
@property
def entity_config(self):
"""Return entity config."""
return self._config.get(CONF_ENTITY_CONFIG, {})
return self._config.get(CONF_ENTITY_CONFIG) or {}

def should_expose(self, entity_id):
"""If an entity should be exposed."""
Expand Down Expand Up @@ -129,6 +129,11 @@ async def _async_prefs_updated(self, prefs):
else:
await self.async_disable_proactive_mode()

# State reporting is reported as a property on entities.
# So when we change it, we need to sync all entities.
await self.async_sync_entities()
return

# If entity prefs are the same or we have filter in config.yaml,
# don't sync.
if (self._cur_entity_prefs is prefs.alexa_entity_configs or
Expand Down Expand Up @@ -190,6 +195,11 @@ async def _sync_prefs(self, _now):

async def async_sync_entities(self):
"""Sync all entities to Alexa."""
# Remove any pending sync
if self._alexa_sync_unsub:
self._alexa_sync_unsub()
self._alexa_sync_unsub = None

to_update = []
to_remove = []

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"""Constants used by Home Assistant components."""
MAJOR_VERSION = 0
MINOR_VERSION = 95
PATCH_VERSION = '2'
PATCH_VERSION = '3'
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
REQUIRED_PYTHON_VER = (3, 5, 3)
Expand Down
23 changes: 20 additions & 3 deletions tests/components/cloud/conftest.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Fixtures for cloud tests."""
import pytest

from unittest.mock import patch

from homeassistant.components.cloud import prefs
import jwt
import pytest

from homeassistant.components.cloud import const, prefs

from . import mock_cloud, mock_cloud_prefs

Expand All @@ -28,3 +29,19 @@ async def cloud_prefs(hass):
cloud_prefs = prefs.CloudPreferences(hass)
await cloud_prefs.async_initialize()
return cloud_prefs


@pytest.fixture
async def mock_cloud_setup(hass):
"""Set up the cloud."""
await mock_cloud(hass)


@pytest.fixture
def mock_cloud_login(hass, mock_cloud_setup):
"""Mock cloud is logged in."""
hass.data[const.DOMAIN].id_token = jwt.encode({
'email': 'hello@home-assistant.io',
'custom:sub-exp': '2018-01-03',
'cognito:username': 'abcdefghjkl',
}, 'test')
154 changes: 154 additions & 0 deletions tests/components/cloud/test_alexa_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
"""Test Alexa config."""
import contextlib
from unittest.mock import patch

from homeassistant.components.cloud import ALEXA_SCHEMA, alexa_config
from homeassistant.util.dt import utcnow
from homeassistant.helpers.entity_registry import EVENT_ENTITY_REGISTRY_UPDATED
from tests.common import mock_coro, async_fire_time_changed


async def test_alexa_config_expose_entity_prefs(hass, cloud_prefs):
"""Test Alexa config should expose using prefs."""
entity_conf = {
'should_expose': False
}
await cloud_prefs.async_update(alexa_entity_configs={
'light.kitchen': entity_conf
})
conf = alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), cloud_prefs, None)

assert not conf.should_expose('light.kitchen')
entity_conf['should_expose'] = True
assert conf.should_expose('light.kitchen')


async def test_alexa_config_report_state(hass, cloud_prefs):
"""Test Alexa config should expose using prefs."""
conf = alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), cloud_prefs, None)

assert cloud_prefs.alexa_report_state is False
assert conf.should_report_state is False
assert conf.is_reporting_states is False

with patch.object(conf, 'async_get_access_token',
return_value=mock_coro("hello")):
await cloud_prefs.async_update(alexa_report_state=True)
await hass.async_block_till_done()

assert cloud_prefs.alexa_report_state is True
assert conf.should_report_state is True
assert conf.is_reporting_states is True

await cloud_prefs.async_update(alexa_report_state=False)
await hass.async_block_till_done()

assert cloud_prefs.alexa_report_state is False
assert conf.should_report_state is False
assert conf.is_reporting_states is False


@contextlib.contextmanager
def patch_sync_helper():
"""Patch sync helper.
In Py3.7 this would have been an async context manager.
"""
to_update = []
to_remove = []

with patch(
'homeassistant.components.cloud.alexa_config.SYNC_DELAY', 0
), patch(
'homeassistant.components.cloud.alexa_config.AlexaConfig._sync_helper',
side_effect=mock_coro
) as mock_helper:
yield to_update, to_remove

actual_to_update, actual_to_remove = mock_helper.mock_calls[0][1]
to_update.extend(actual_to_update)
to_remove.extend(actual_to_remove)


async def test_alexa_update_expose_trigger_sync(hass, cloud_prefs):
"""Test Alexa config responds to updating exposed entities."""
alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), cloud_prefs, None)

with patch_sync_helper() as (to_update, to_remove):
await cloud_prefs.async_update_alexa_entity_config(
entity_id='light.kitchen', should_expose=True
)
await hass.async_block_till_done()
async_fire_time_changed(hass, utcnow())
await hass.async_block_till_done()

assert to_update == ['light.kitchen']
assert to_remove == []

with patch_sync_helper() as (to_update, to_remove):
await cloud_prefs.async_update_alexa_entity_config(
entity_id='light.kitchen', should_expose=False
)
await cloud_prefs.async_update_alexa_entity_config(
entity_id='binary_sensor.door', should_expose=True
)
await cloud_prefs.async_update_alexa_entity_config(
entity_id='sensor.temp', should_expose=True
)
await hass.async_block_till_done()
async_fire_time_changed(hass, utcnow())
await hass.async_block_till_done()

assert sorted(to_update) == ['binary_sensor.door', 'sensor.temp']
assert to_remove == ['light.kitchen']


async def test_alexa_entity_registry_sync(hass, mock_cloud_login, cloud_prefs):
"""Test Alexa config responds to entity registry."""
alexa_config.AlexaConfig(
hass, ALEXA_SCHEMA({}), cloud_prefs, hass.data['cloud'])

with patch_sync_helper() as (to_update, to_remove):
hass.bus.async_fire(EVENT_ENTITY_REGISTRY_UPDATED, {
'action': 'create',
'entity_id': 'light.kitchen',
})
await hass.async_block_till_done()

assert to_update == ['light.kitchen']
assert to_remove == []

with patch_sync_helper() as (to_update, to_remove):
hass.bus.async_fire(EVENT_ENTITY_REGISTRY_UPDATED, {
'action': 'remove',
'entity_id': 'light.kitchen',
})
await hass.async_block_till_done()

assert to_update == []
assert to_remove == ['light.kitchen']

with patch_sync_helper() as (to_update, to_remove):
hass.bus.async_fire(EVENT_ENTITY_REGISTRY_UPDATED, {
'action': 'update',
'entity_id': 'light.kitchen',
})
await hass.async_block_till_done()

assert to_update == []
assert to_remove == []


async def test_alexa_update_report_state(hass, cloud_prefs):
"""Test Alexa config responds to reporting state."""
alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), cloud_prefs, None)

with patch(
'homeassistant.components.cloud.alexa_config.AlexaConfig.'
'async_sync_entities', side_effect=mock_coro) as mock_sync, patch(
'homeassistant.components.cloud.alexa_config.'
'AlexaConfig.async_enable_proactive_mode', side_effect=mock_coro):
await cloud_prefs.async_update(alexa_report_state=True)
await hass.async_block_till_done()

assert len(mock_sync.mock_calls) == 1
Loading

0 comments on commit 2e9c71f

Please sign in to comment.