Only lookup unknown Google Cast models once (#71348)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
Erik Montnemery
2022-05-05 14:43:30 -07:00
committed by Paulus Schoutsen
co-authored by Paulus Schoutsen
parent b8dccbbbf3
commit f2a07254a4
9 changed files with 166 additions and 19 deletions
+11
View File
@@ -14,6 +14,13 @@ def get_multizone_status_mock():
return mock
@pytest.fixture()
def get_cast_type_mock():
"""Mock pychromecast dial."""
mock = MagicMock(spec_set=pychromecast.dial.get_cast_type)
return mock
@pytest.fixture()
def castbrowser_mock():
"""Mock pychromecast CastBrowser."""
@@ -43,6 +50,7 @@ def cast_mock(
mz_mock,
quick_play_mock,
castbrowser_mock,
get_cast_type_mock,
get_chromecast_mock,
get_multizone_status_mock,
):
@@ -52,6 +60,9 @@ def cast_mock(
with patch(
"homeassistant.components.cast.discovery.pychromecast.discovery.CastBrowser",
castbrowser_mock,
), patch(
"homeassistant.components.cast.helpers.dial.get_cast_type",
get_cast_type_mock,
), patch(
"homeassistant.components.cast.helpers.dial.get_multizone_status",
get_multizone_status_mock,
+105 -4
View File
@@ -64,6 +64,8 @@ FAKE_MDNS_SERVICE = pychromecast.discovery.ServiceInfo(
pychromecast.const.SERVICE_TYPE_MDNS, "the-service"
)
UNDEFINED = object()
def get_fake_chromecast(info: ChromecastInfo):
"""Generate a Fake Chromecast object with the specified arguments."""
@@ -74,7 +76,14 @@ def get_fake_chromecast(info: ChromecastInfo):
def get_fake_chromecast_info(
host="192.168.178.42", port=8009, service=None, uuid: UUID | None = FakeUUID
*,
host="192.168.178.42",
port=8009,
service=None,
uuid: UUID | None = FakeUUID,
cast_type=UNDEFINED,
manufacturer=UNDEFINED,
model_name=UNDEFINED,
):
"""Generate a Fake ChromecastInfo with the specified arguments."""
@@ -82,16 +91,22 @@ def get_fake_chromecast_info(
service = pychromecast.discovery.ServiceInfo(
pychromecast.const.SERVICE_TYPE_HOST, (host, port)
)
if cast_type is UNDEFINED:
cast_type = CAST_TYPE_GROUP if port != 8009 else CAST_TYPE_CHROMECAST
if manufacturer is UNDEFINED:
manufacturer = "Nabu Casa"
if model_name is UNDEFINED:
model_name = "Chromecast"
return ChromecastInfo(
cast_info=pychromecast.models.CastInfo(
services={service},
uuid=uuid,
model_name="Chromecast",
model_name=model_name,
friendly_name="Speaker",
host=host,
port=port,
cast_type=CAST_TYPE_GROUP if port != 8009 else CAST_TYPE_CHROMECAST,
manufacturer="Nabu Casa",
cast_type=cast_type,
manufacturer=manufacturer,
)
)
@@ -342,6 +357,92 @@ async def test_internal_discovery_callback_fill_out_group(
get_multizone_status_mock.assert_called_once()
async def test_internal_discovery_callback_fill_out_cast_type_manufacturer(
hass, get_cast_type_mock, caplog
):
"""Test internal discovery automatically filling out information."""
discover_cast, _, _ = await async_setup_cast_internal_discovery(hass)
info = get_fake_chromecast_info(
host="host1",
port=8009,
service=FAKE_MDNS_SERVICE,
cast_type=None,
manufacturer=None,
)
info2 = get_fake_chromecast_info(
host="host1",
port=8009,
service=FAKE_MDNS_SERVICE,
cast_type=None,
manufacturer=None,
model_name="Model 101",
)
zconf = get_fake_zconf(host="host1", port=8009)
full_info = attr.evolve(
info,
cast_info=pychromecast.discovery.CastInfo(
services=info.cast_info.services,
uuid=FakeUUID,
model_name="Chromecast",
friendly_name="Speaker",
host=info.cast_info.host,
port=info.cast_info.port,
cast_type="audio",
manufacturer="TrollTech",
),
is_dynamic_group=None,
)
full_info2 = attr.evolve(
info2,
cast_info=pychromecast.discovery.CastInfo(
services=info.cast_info.services,
uuid=FakeUUID,
model_name="Model 101",
friendly_name="Speaker",
host=info.cast_info.host,
port=info.cast_info.port,
cast_type="cast",
manufacturer="Cyberdyne Systems",
),
is_dynamic_group=None,
)
get_cast_type_mock.assert_not_called()
get_cast_type_mock.return_value = full_info.cast_info
with patch(
"homeassistant.components.cast.discovery.ChromeCastZeroconf.get_zeroconf",
return_value=zconf,
):
signal = MagicMock()
async_dispatcher_connect(hass, "cast_discovered", signal)
discover_cast(FAKE_MDNS_SERVICE, info)
await hass.async_block_till_done()
# when called with incomplete info, it should use HTTP to get missing
get_cast_type_mock.assert_called_once()
assert get_cast_type_mock.call_count == 1
discover = signal.mock_calls[0][1][0]
assert discover == full_info
assert "Fetched cast details for unknown model 'Chromecast'" in caplog.text
# Call again, the model name should be fetched from cache
discover_cast(FAKE_MDNS_SERVICE, info)
await hass.async_block_till_done()
assert get_cast_type_mock.call_count == 1 # No additional calls
discover = signal.mock_calls[1][1][0]
assert discover == full_info
# Call for another model, need to call HTTP again
get_cast_type_mock.return_value = full_info2.cast_info
discover_cast(FAKE_MDNS_SERVICE, info2)
await hass.async_block_till_done()
assert get_cast_type_mock.call_count == 2
discover = signal.mock_calls[2][1][0]
assert discover == full_info2
async def test_stop_discovery_called_on_stop(hass, castbrowser_mock):
"""Test pychromecast.stop_discovery called on shutdown."""
# start_discovery should be called with empty config