2019-01-31 01:31:59 +00:00
|
|
|
"""Tests for the smartapp module."""
|
|
|
|
from uuid import uuid4
|
|
|
|
|
2019-07-09 02:39:55 +00:00
|
|
|
from asynctest import CoroutineMock, Mock, patch
|
2019-02-08 04:51:17 +00:00
|
|
|
from pysmartthings import AppEntity, Capability
|
2019-01-31 01:31:59 +00:00
|
|
|
|
|
|
|
from homeassistant.components.smartthings import smartapp
|
2019-02-22 19:35:12 +00:00
|
|
|
from homeassistant.components.smartthings.const import (
|
|
|
|
CONF_INSTALLED_APP_ID, CONF_INSTALLED_APPS, CONF_LOCATION_ID,
|
|
|
|
CONF_REFRESH_TOKEN, DATA_MANAGER, DOMAIN)
|
2019-01-31 01:31:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_update_app(hass, app):
|
|
|
|
"""Test update_app does not save if app is current."""
|
|
|
|
await smartapp.update_app(hass, app)
|
|
|
|
assert app.save.call_count == 0
|
|
|
|
|
|
|
|
|
|
|
|
async def test_update_app_updated_needed(hass, app):
|
|
|
|
"""Test update_app updates when an app is needed."""
|
2019-07-09 02:39:55 +00:00
|
|
|
mock_app = Mock(AppEntity)
|
2019-01-31 01:31:59 +00:00
|
|
|
mock_app.app_name = 'Test'
|
|
|
|
|
|
|
|
await smartapp.update_app(hass, mock_app)
|
|
|
|
|
|
|
|
assert mock_app.save.call_count == 1
|
|
|
|
assert mock_app.app_name == 'Test'
|
|
|
|
assert mock_app.display_name == app.display_name
|
|
|
|
assert mock_app.description == app.description
|
|
|
|
assert mock_app.webhook_target_url == app.webhook_target_url
|
|
|
|
assert mock_app.app_type == app.app_type
|
|
|
|
assert mock_app.single_instance == app.single_instance
|
|
|
|
assert mock_app.classifications == app.classifications
|
|
|
|
|
|
|
|
|
2019-02-22 19:35:12 +00:00
|
|
|
async def test_smartapp_install_store_if_no_other(
|
2019-02-08 04:51:17 +00:00
|
|
|
hass, smartthings_mock, device_factory):
|
2019-01-31 01:31:59 +00:00
|
|
|
"""Test aborts if no other app was configured already."""
|
2019-02-08 04:51:17 +00:00
|
|
|
# Arrange
|
2019-01-31 01:31:59 +00:00
|
|
|
app = Mock()
|
|
|
|
app.app_id = uuid4()
|
|
|
|
request = Mock()
|
2019-02-22 19:35:12 +00:00
|
|
|
request.installed_app_id = str(uuid4())
|
|
|
|
request.auth_token = str(uuid4())
|
|
|
|
request.location_id = str(uuid4())
|
|
|
|
request.refresh_token = str(uuid4())
|
2019-02-08 04:51:17 +00:00
|
|
|
# Act
|
2019-01-31 01:31:59 +00:00
|
|
|
await smartapp.smartapp_install(hass, request, None, app)
|
2019-02-08 04:51:17 +00:00
|
|
|
# Assert
|
2019-01-31 01:31:59 +00:00
|
|
|
entries = hass.config_entries.async_entries('smartthings')
|
|
|
|
assert not entries
|
2019-02-22 19:35:12 +00:00
|
|
|
data = hass.data[DOMAIN][CONF_INSTALLED_APPS][0]
|
|
|
|
assert data[CONF_REFRESH_TOKEN] == request.refresh_token
|
|
|
|
assert data[CONF_LOCATION_ID] == request.location_id
|
|
|
|
assert data[CONF_INSTALLED_APP_ID] == request.installed_app_id
|
2019-01-31 01:31:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_smartapp_install_creates_flow(
|
2019-02-08 04:51:17 +00:00
|
|
|
hass, smartthings_mock, config_entry, location, device_factory):
|
2019-01-31 01:31:59 +00:00
|
|
|
"""Test installation creates flow."""
|
|
|
|
# Arrange
|
|
|
|
setattr(hass.config_entries, '_entries', [config_entry])
|
|
|
|
app = Mock()
|
|
|
|
app.app_id = config_entry.data['app_id']
|
|
|
|
request = Mock()
|
|
|
|
request.installed_app_id = str(uuid4())
|
|
|
|
request.auth_token = str(uuid4())
|
2019-02-22 19:35:12 +00:00
|
|
|
request.refresh_token = str(uuid4())
|
2019-01-31 01:31:59 +00:00
|
|
|
request.location_id = location.location_id
|
2019-02-08 04:51:17 +00:00
|
|
|
devices = [
|
|
|
|
device_factory('', [Capability.battery, 'ping']),
|
|
|
|
device_factory('', [Capability.switch, Capability.switch_level]),
|
|
|
|
device_factory('', [Capability.switch])
|
|
|
|
]
|
2019-07-09 02:39:55 +00:00
|
|
|
smartthings_mock.devices.return_value = devices
|
2019-01-31 01:31:59 +00:00
|
|
|
# Act
|
|
|
|
await smartapp.smartapp_install(hass, request, None, app)
|
|
|
|
# Assert
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
entries = hass.config_entries.async_entries('smartthings')
|
|
|
|
assert len(entries) == 2
|
|
|
|
assert entries[1].data['app_id'] == app.app_id
|
|
|
|
assert entries[1].data['installed_app_id'] == request.installed_app_id
|
|
|
|
assert entries[1].data['location_id'] == request.location_id
|
|
|
|
assert entries[1].data['access_token'] == \
|
|
|
|
config_entry.data['access_token']
|
2019-02-22 19:35:12 +00:00
|
|
|
assert entries[1].data['refresh_token'] == request.refresh_token
|
|
|
|
assert entries[1].data['client_secret'] == \
|
|
|
|
config_entry.data['client_secret']
|
|
|
|
assert entries[1].data['client_id'] == config_entry.data['client_id']
|
2019-01-31 01:31:59 +00:00
|
|
|
assert entries[1].title == location.name
|
|
|
|
|
|
|
|
|
2019-02-22 19:35:12 +00:00
|
|
|
async def test_smartapp_update_saves_token(
|
|
|
|
hass, smartthings_mock, location, device_factory):
|
|
|
|
"""Test update saves token."""
|
2019-02-08 04:51:17 +00:00
|
|
|
# Arrange
|
2019-02-22 19:35:12 +00:00
|
|
|
entry = Mock()
|
|
|
|
entry.data = {
|
|
|
|
'installed_app_id': str(uuid4()),
|
|
|
|
'app_id': str(uuid4())
|
|
|
|
}
|
|
|
|
entry.domain = DOMAIN
|
|
|
|
|
|
|
|
setattr(hass.config_entries, '_entries', [entry])
|
2019-02-08 04:51:17 +00:00
|
|
|
app = Mock()
|
2019-02-22 19:35:12 +00:00
|
|
|
app.app_id = entry.data['app_id']
|
2019-02-08 04:51:17 +00:00
|
|
|
request = Mock()
|
2019-02-22 19:35:12 +00:00
|
|
|
request.installed_app_id = entry.data['installed_app_id']
|
2019-02-08 04:51:17 +00:00
|
|
|
request.auth_token = str(uuid4())
|
2019-02-22 19:35:12 +00:00
|
|
|
request.refresh_token = str(uuid4())
|
2019-02-08 04:51:17 +00:00
|
|
|
request.location_id = location.location_id
|
2019-02-22 19:35:12 +00:00
|
|
|
|
2019-02-08 04:51:17 +00:00
|
|
|
# Act
|
|
|
|
await smartapp.smartapp_update(hass, request, None, app)
|
|
|
|
# Assert
|
2019-02-22 19:35:12 +00:00
|
|
|
assert entry.data[CONF_REFRESH_TOKEN] == request.refresh_token
|
2019-02-08 04:51:17 +00:00
|
|
|
|
|
|
|
|
2019-01-31 01:31:59 +00:00
|
|
|
async def test_smartapp_uninstall(hass, config_entry):
|
|
|
|
"""Test the config entry is unloaded when the app is uninstalled."""
|
|
|
|
setattr(hass.config_entries, '_entries', [config_entry])
|
|
|
|
app = Mock()
|
|
|
|
app.app_id = config_entry.data['app_id']
|
|
|
|
request = Mock()
|
|
|
|
request.installed_app_id = config_entry.data['installed_app_id']
|
|
|
|
|
2019-07-09 02:39:55 +00:00
|
|
|
with patch.object(hass.config_entries, 'async_remove') as remove:
|
2019-01-31 01:31:59 +00:00
|
|
|
await smartapp.smartapp_uninstall(hass, request, None, app)
|
|
|
|
assert remove.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
async def test_smartapp_webhook(hass):
|
|
|
|
"""Test the smartapp webhook calls the manager."""
|
|
|
|
manager = Mock()
|
2019-07-09 02:39:55 +00:00
|
|
|
manager.handle_request = CoroutineMock(return_value={})
|
2019-01-31 01:31:59 +00:00
|
|
|
hass.data[DOMAIN][DATA_MANAGER] = manager
|
|
|
|
request = Mock()
|
|
|
|
request.headers = []
|
2019-07-09 02:39:55 +00:00
|
|
|
request.json = CoroutineMock(return_value={})
|
2019-01-31 01:31:59 +00:00
|
|
|
result = await smartapp.smartapp_webhook(hass, '', request)
|
|
|
|
|
|
|
|
assert result.body == b'{}'
|
2019-02-22 19:35:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_smartapp_sync_subscriptions(
|
|
|
|
hass, smartthings_mock, device_factory, subscription_factory):
|
|
|
|
"""Test synchronization adds and removes."""
|
2019-07-09 02:39:55 +00:00
|
|
|
smartthings_mock.subscriptions.return_value = [
|
2019-02-22 19:35:12 +00:00
|
|
|
subscription_factory(Capability.thermostat),
|
|
|
|
subscription_factory(Capability.switch),
|
|
|
|
subscription_factory(Capability.switch_level)
|
|
|
|
]
|
|
|
|
devices = [
|
|
|
|
device_factory('', [Capability.battery, 'ping']),
|
|
|
|
device_factory('', [Capability.switch, Capability.switch_level]),
|
|
|
|
device_factory('', [Capability.switch])
|
|
|
|
]
|
|
|
|
|
|
|
|
await smartapp.smartapp_sync_subscriptions(
|
|
|
|
hass, str(uuid4()), str(uuid4()), str(uuid4()), devices)
|
|
|
|
|
2019-07-09 02:39:55 +00:00
|
|
|
assert smartthings_mock.subscriptions.call_count == 1
|
|
|
|
assert smartthings_mock.delete_subscription.call_count == 1
|
|
|
|
assert smartthings_mock.create_subscription.call_count == 1
|
2019-02-22 19:35:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_smartapp_sync_subscriptions_up_to_date(
|
|
|
|
hass, smartthings_mock, device_factory, subscription_factory):
|
|
|
|
"""Test synchronization does nothing when current."""
|
2019-07-09 02:39:55 +00:00
|
|
|
smartthings_mock.subscriptions.return_value = [
|
2019-02-22 19:35:12 +00:00
|
|
|
subscription_factory(Capability.battery),
|
|
|
|
subscription_factory(Capability.switch),
|
|
|
|
subscription_factory(Capability.switch_level)
|
|
|
|
]
|
|
|
|
devices = [
|
|
|
|
device_factory('', [Capability.battery, 'ping']),
|
|
|
|
device_factory('', [Capability.switch, Capability.switch_level]),
|
|
|
|
device_factory('', [Capability.switch])
|
|
|
|
]
|
|
|
|
|
|
|
|
await smartapp.smartapp_sync_subscriptions(
|
|
|
|
hass, str(uuid4()), str(uuid4()), str(uuid4()), devices)
|
|
|
|
|
2019-07-09 02:39:55 +00:00
|
|
|
assert smartthings_mock.subscriptions.call_count == 1
|
|
|
|
assert smartthings_mock.delete_subscription.call_count == 0
|
|
|
|
assert smartthings_mock.create_subscription.call_count == 0
|
2019-02-22 19:35:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_smartapp_sync_subscriptions_handles_exceptions(
|
|
|
|
hass, smartthings_mock, device_factory, subscription_factory):
|
|
|
|
"""Test synchronization does nothing when current."""
|
2019-07-09 02:39:55 +00:00
|
|
|
smartthings_mock.delete_subscription.side_effect = Exception
|
|
|
|
smartthings_mock.create_subscription.side_effect = Exception
|
|
|
|
smartthings_mock.subscriptions.return_value = [
|
2019-02-22 19:35:12 +00:00
|
|
|
subscription_factory(Capability.battery),
|
|
|
|
subscription_factory(Capability.switch),
|
|
|
|
subscription_factory(Capability.switch_level)
|
|
|
|
]
|
|
|
|
devices = [
|
|
|
|
device_factory('', [Capability.thermostat, 'ping']),
|
|
|
|
device_factory('', [Capability.switch, Capability.switch_level]),
|
|
|
|
device_factory('', [Capability.switch])
|
|
|
|
]
|
|
|
|
|
|
|
|
await smartapp.smartapp_sync_subscriptions(
|
|
|
|
hass, str(uuid4()), str(uuid4()), str(uuid4()), devices)
|
|
|
|
|
2019-07-09 02:39:55 +00:00
|
|
|
assert smartthings_mock.subscriptions.call_count == 1
|
|
|
|
assert smartthings_mock.delete_subscription.call_count == 1
|
|
|
|
assert smartthings_mock.create_subscription.call_count == 1
|