Convert discovery tests to async (#64411)

This commit is contained in:
Paulus Schoutsen 2022-01-19 03:21:15 -08:00 committed by GitHub
parent e6c7c01e6c
commit 8d7cca9774
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,215 +1,189 @@
"""Test discovery helpers.""" """Test discovery helpers."""
from unittest.mock import patch from unittest.mock import patch
import pytest
from homeassistant import setup from homeassistant import setup
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
from homeassistant.helpers.dispatcher import dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.util.async_ import run_callback_threadsafe
from tests.common import ( from tests.common import (
MockModule, MockModule,
MockPlatform, MockPlatform,
get_test_home_assistant,
mock_coro,
mock_entity_platform, mock_entity_platform,
mock_integration, mock_integration,
) )
class TestHelpersDiscovery: @pytest.fixture
"""Tests for discovery helper methods.""" def mock_setup_component():
"""Mock setup component."""
with patch("homeassistant.setup.async_setup_component", return_value=True) as mock:
yield mock
def setup_method(self, method):
"""Set up things to be run when tests are started."""
self.hass = get_test_home_assistant()
def teardown_method(self, method): async def test_listen(hass, mock_setup_component):
"""Stop everything that was started.""" """Test discovery listen/discover combo."""
self.hass.stop() calls_single = []
@patch("homeassistant.setup.async_setup_component", return_value=mock_coro()) @callback
def test_listen(self, mock_setup_component): def callback_single(service, info):
"""Test discovery listen/discover combo.""" """Service discovered callback."""
helpers = self.hass.helpers calls_single.append((service, info))
calls_single = []
@callback discovery.async_listen(hass, "test service", callback_single)
def callback_single(service, info):
"""Service discovered callback."""
calls_single.append((service, info))
self.hass.add_job( await discovery.async_discover(
helpers.discovery.async_listen, "test service", callback_single hass,
) "test service",
"discovery info",
"test_component",
{},
)
await hass.async_block_till_done()
self.hass.add_job( assert mock_setup_component.called
helpers.discovery.async_discover, assert mock_setup_component.call_args[0] == (hass, "test_component", {})
"test service", assert len(calls_single) == 1
"discovery info", assert calls_single[0] == ("test service", "discovery info")
"test_component",
{},
)
self.hass.block_till_done()
assert mock_setup_component.called
assert mock_setup_component.call_args[0] == (self.hass, "test_component", {})
assert len(calls_single) == 1
assert calls_single[0] == ("test service", "discovery info")
@patch("homeassistant.setup.async_setup_component", return_value=mock_coro(True)) async def test_platform(hass, mock_setup_component):
def test_platform(self, mock_setup_component): """Test discover platform method."""
"""Test discover platform method.""" calls = []
calls = []
@callback @callback
def platform_callback(platform, info): def platform_callback(platform, info):
"""Platform callback method.""" """Platform callback method."""
calls.append((platform, info)) calls.append((platform, info))
run_callback_threadsafe( discovery.async_listen_platform(
self.hass.loop, hass,
discovery.async_listen_platform, "test_component",
self.hass, platform_callback,
"test_component", )
platform_callback,
).result()
await discovery.async_load_platform(
hass,
"test_component",
"test_platform",
"discovery info",
{"test_component": {}},
)
await hass.async_block_till_done()
assert mock_setup_component.called
assert mock_setup_component.call_args[0] == (
hass,
"test_component",
{"test_component": {}},
)
await hass.async_block_till_done()
await hass.async_add_executor_job(
discovery.load_platform,
hass,
"test_component_2",
"test_platform",
"discovery info",
{"test_component": {}},
)
await hass.async_block_till_done()
assert len(calls) == 1
assert calls[0] == ("test_platform", "discovery info")
async_dispatcher_send(
hass,
discovery.SIGNAL_PLATFORM_DISCOVERED,
{"service": discovery.EVENT_LOAD_PLATFORM.format("test_component")},
)
await hass.async_block_till_done()
assert len(calls) == 1
async def test_circular_import(hass):
"""Test we don't break doing circular import.
This test will have test_component discover the switch.test_circular
component while setting up.
The supplied config will load test_component and will load
switch.test_circular.
That means that after startup, we will have test_component and switch
setup. The test_circular platform has been loaded twice.
"""
component_calls = []
platform_calls = []
def component_setup(hass, config):
"""Set up mock component."""
discovery.load_platform( discovery.load_platform(
self.hass, hass, Platform.SWITCH, "test_circular", {"key": "value"}, config
"test_component",
"test_platform",
"discovery info",
{"test_component": {}},
) )
self.hass.block_till_done() component_calls.append(1)
assert mock_setup_component.called return True
assert mock_setup_component.call_args[0] == (
self.hass, def setup_platform(hass, config, add_entities_callback, discovery_info=None):
"test_component", """Set up mock platform."""
{"test_component": {}}, platform_calls.append("disc" if discovery_info else "component")
mock_integration(hass, MockModule("test_component", setup=component_setup))
# dependencies are only set in component level
# since we are using manifest to hold them
mock_integration(hass, MockModule("test_circular", dependencies=["test_component"]))
mock_entity_platform(hass, "switch.test_circular", MockPlatform(setup_platform))
await setup.async_setup_component(
hass,
"test_component",
{"test_component": None, "switch": [{"platform": "test_circular"}]},
)
await hass.async_block_till_done()
# test_component will only be setup once
assert len(component_calls) == 1
# The platform will be setup once via the config in `setup_component`
# and once via the discovery inside test_component.
assert len(platform_calls) == 2
assert "test_component" in hass.config.components
assert "switch" in hass.config.components
async def test_1st_discovers_2nd_component(hass):
"""Test that we don't break if one component discovers the other.
If the first component fires a discovery event to set up the
second component while the second component is about to be set up,
it should not set up the second component twice.
"""
component_calls = []
async def component1_setup(hass, config):
"""Set up mock component."""
print("component1 setup")
await discovery.async_discover(
hass, "test_component2", {}, "test_component2", {}
) )
self.hass.block_till_done() return True
discovery.load_platform( def component2_setup(hass, config):
self.hass, """Set up mock component."""
"test_component_2", component_calls.append(1)
"test_platform", return True
"discovery info",
{"test_component": {}},
)
self.hass.block_till_done()
assert len(calls) == 1 mock_integration(hass, MockModule("test_component1", async_setup=component1_setup))
assert calls[0] == ("test_platform", "discovery info")
dispatcher_send( mock_integration(hass, MockModule("test_component2", setup=component2_setup))
self.hass,
discovery.SIGNAL_PLATFORM_DISCOVERED,
{"service": discovery.EVENT_LOAD_PLATFORM.format("test_component")},
)
self.hass.block_till_done()
assert len(calls) == 1 hass.async_create_task(setup.async_setup_component(hass, "test_component1", {}))
hass.async_create_task(setup.async_setup_component(hass, "test_component2", {}))
await hass.async_block_till_done()
def test_circular_import(self): # test_component will only be setup once
"""Test we don't break doing circular import. assert len(component_calls) == 1
This test will have test_component discover the switch.test_circular
component while setting up.
The supplied config will load test_component and will load
switch.test_circular.
That means that after startup, we will have test_component and switch
setup. The test_circular platform has been loaded twice.
"""
component_calls = []
platform_calls = []
def component_setup(hass, config):
"""Set up mock component."""
discovery.load_platform(
hass, Platform.SWITCH, "test_circular", {"key": "value"}, config
)
component_calls.append(1)
return True
def setup_platform(hass, config, add_entities_callback, discovery_info=None):
"""Set up mock platform."""
platform_calls.append("disc" if discovery_info else "component")
mock_integration(self.hass, MockModule("test_component", setup=component_setup))
# dependencies are only set in component level
# since we are using manifest to hold them
mock_integration(
self.hass, MockModule("test_circular", dependencies=["test_component"])
)
mock_entity_platform(
self.hass, "switch.test_circular", MockPlatform(setup_platform)
)
setup.setup_component(
self.hass,
"test_component",
{"test_component": None, "switch": [{"platform": "test_circular"}]},
)
self.hass.block_till_done()
# test_component will only be setup once
assert len(component_calls) == 1
# The platform will be setup once via the config in `setup_component`
# and once via the discovery inside test_component.
assert len(platform_calls) == 2
assert "test_component" in self.hass.config.components
assert "switch" in self.hass.config.components
@patch("homeassistant.helpers.signal.async_register_signal_handling")
def test_1st_discovers_2nd_component(self, mock_signal):
"""Test that we don't break if one component discovers the other.
If the first component fires a discovery event to set up the
second component while the second component is about to be set up,
it should not set up the second component twice.
"""
component_calls = []
async def component1_setup(hass, config):
"""Set up mock component."""
print("component1 setup")
await discovery.async_discover(
hass, "test_component2", {}, "test_component2", {}
)
return True
def component2_setup(hass, config):
"""Set up mock component."""
component_calls.append(1)
return True
mock_integration(
self.hass, MockModule("test_component1", async_setup=component1_setup)
)
mock_integration(
self.hass, MockModule("test_component2", setup=component2_setup)
)
@callback
def do_setup():
"""Set up 2 components."""
self.hass.async_add_job(
setup.async_setup_component(self.hass, "test_component1", {})
)
self.hass.async_add_job(
setup.async_setup_component(self.hass, "test_component2", {})
)
self.hass.add_job(do_setup)
self.hass.block_till_done()
# test_component will only be setup once
assert len(component_calls) == 1