hass-core/tests/components/discovery/test_init.py
J. Nick Koston 5cf7b1b1bc
Ensure we do not start discovered flows until after the started event has fired (#38047)
* Ensure we do not start discovered flows until after the start event has fired

This change makes zeroconf and ssdp match discovery behavior of not
creating config flows until the start event has been fired.  This
prevents config flow creation/dependency installs for discovered
config flows from competing for cpu time during startup.

* Start discovery/service browser/ssdp when EVENT_HOMEASSISTANT_STARTED is fired instead of EVENT_HOMEASSISTANT_START
2020-07-21 14:18:43 -10:00

164 lines
5 KiB
Python

"""The tests for the discovery component."""
from unittest.mock import MagicMock
import pytest
from homeassistant import config_entries
from homeassistant.bootstrap import async_setup_component
from homeassistant.components import discovery
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED
from homeassistant.util.dt import utcnow
from tests.async_mock import patch
from tests.common import async_fire_time_changed, mock_coro
# One might consider to "mock" services, but it's easy enough to just use
# what is already available.
SERVICE = "yamaha"
SERVICE_COMPONENT = "media_player"
SERVICE_NO_PLATFORM = "hass_ios"
SERVICE_NO_PLATFORM_COMPONENT = "ios"
SERVICE_INFO = {"key": "value"} # Can be anything
UNKNOWN_SERVICE = "this_service_will_never_be_supported"
BASE_CONFIG = {discovery.DOMAIN: {"ignore": [], "enable": []}}
IGNORE_CONFIG = {discovery.DOMAIN: {"ignore": [SERVICE_NO_PLATFORM]}}
@pytest.fixture(autouse=True)
def netdisco_mock():
"""Mock netdisco."""
with patch.dict("sys.modules", {"netdisco.discovery": MagicMock()}):
yield
async def mock_discovery(hass, discoveries, config=BASE_CONFIG):
"""Mock discoveries."""
with patch("homeassistant.components.zeroconf.async_get_instance"):
assert await async_setup_component(hass, "discovery", config)
await hass.async_block_till_done()
await hass.async_start()
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done()
with patch.object(discovery, "_discover", discoveries), patch(
"homeassistant.components.discovery.async_discover", return_value=mock_coro()
) as mock_discover, patch(
"homeassistant.components.discovery.async_load_platform",
return_value=mock_coro(),
) as mock_platform:
async_fire_time_changed(hass, utcnow())
# Work around an issue where our loop.call_soon not get caught
await hass.async_block_till_done()
await hass.async_block_till_done()
return mock_discover, mock_platform
async def test_unknown_service(hass):
"""Test that unknown service is ignored."""
def discover(netdisco, zeroconf_instance):
"""Fake discovery."""
return [("this_service_will_never_be_supported", {"info": "some"})]
mock_discover, mock_platform = await mock_discovery(hass, discover)
assert not mock_discover.called
assert not mock_platform.called
async def test_load_platform(hass):
"""Test load a platform."""
def discover(netdisco, zeroconf_instance):
"""Fake discovery."""
return [(SERVICE, SERVICE_INFO)]
mock_discover, mock_platform = await mock_discovery(hass, discover)
assert not mock_discover.called
assert mock_platform.called
mock_platform.assert_called_with(
hass, SERVICE_COMPONENT, SERVICE, SERVICE_INFO, BASE_CONFIG
)
async def test_load_component(hass):
"""Test load a component."""
def discover(netdisco, zeroconf_instance):
"""Fake discovery."""
return [(SERVICE_NO_PLATFORM, SERVICE_INFO)]
mock_discover, mock_platform = await mock_discovery(hass, discover)
assert mock_discover.called
assert not mock_platform.called
mock_discover.assert_called_with(
hass,
SERVICE_NO_PLATFORM,
SERVICE_INFO,
SERVICE_NO_PLATFORM_COMPONENT,
BASE_CONFIG,
)
async def test_ignore_service(hass):
"""Test ignore service."""
def discover(netdisco, zeroconf_instance):
"""Fake discovery."""
return [(SERVICE_NO_PLATFORM, SERVICE_INFO)]
mock_discover, mock_platform = await mock_discovery(hass, discover, IGNORE_CONFIG)
assert not mock_discover.called
assert not mock_platform.called
async def test_discover_duplicates(hass):
"""Test load a component."""
def discover(netdisco, zeroconf_instance):
"""Fake discovery."""
return [
(SERVICE_NO_PLATFORM, SERVICE_INFO),
(SERVICE_NO_PLATFORM, SERVICE_INFO),
]
mock_discover, mock_platform = await mock_discovery(hass, discover)
assert mock_discover.called
assert mock_discover.call_count == 1
assert not mock_platform.called
mock_discover.assert_called_with(
hass,
SERVICE_NO_PLATFORM,
SERVICE_INFO,
SERVICE_NO_PLATFORM_COMPONENT,
BASE_CONFIG,
)
async def test_discover_config_flow(hass):
"""Test discovery triggering a config flow."""
discovery_info = {"hello": "world"}
def discover(netdisco, zeroconf_instance):
"""Fake discovery."""
return [("mock-service", discovery_info)]
with patch.dict(
discovery.CONFIG_ENTRY_HANDLERS, {"mock-service": "mock-component"}
), patch("homeassistant.data_entry_flow.FlowManager.async_init") as m_init:
await mock_discovery(hass, discover)
assert len(m_init.mock_calls) == 1
args, kwargs = m_init.mock_calls[0][1:]
assert args == ("mock-component",)
assert kwargs["context"]["source"] == config_entries.SOURCE_DISCOVERY
assert kwargs["data"] == discovery_info