From 7359013db0923054a8502995076a678450e650ac Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Tue, 4 Mar 2025 20:24:36 +0100 Subject: [PATCH] Move ForkedDaapdUpdater setup to __init__ module (#139733) * Move ForkedDaapdUpdater setup to __init__ module * Adjust tests * One more --- .../components/forked_daapd/__init__.py | 18 ++++++++++++++- .../components/forked_daapd/coordinator.py | 5 ++++ .../components/forked_daapd/media_player.py | 23 ++++++------------- .../forked_daapd/test_browse_media.py | 8 +++---- .../forked_daapd/test_config_flow.py | 19 ++++++++------- .../forked_daapd/test_media_player.py | 4 ++-- 6 files changed, 44 insertions(+), 33 deletions(-) diff --git a/homeassistant/components/forked_daapd/__init__.py b/homeassistant/components/forked_daapd/__init__.py index 2172e60ba38..16fd96ee365 100644 --- a/homeassistant/components/forked_daapd/__init__.py +++ b/homeassistant/components/forked_daapd/__init__.py @@ -1,16 +1,32 @@ """The forked_daapd component.""" +from pyforked_daapd import ForkedDaapdAPI + from homeassistant.config_entries import ConfigEntry -from homeassistant.const import Platform +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, Platform from homeassistant.core import HomeAssistant +from homeassistant.helpers.aiohttp_client import async_get_clientsession from .const import DOMAIN, HASS_DATA_UPDATER_KEY +from .coordinator import ForkedDaapdUpdater PLATFORMS = [Platform.MEDIA_PLAYER] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up forked-daapd from a config entry by forwarding to platform.""" + host: str = entry.data[CONF_HOST] + port: int = entry.data[CONF_PORT] + password: str = entry.data[CONF_PASSWORD] + forked_daapd_api = ForkedDaapdAPI( + async_get_clientsession(hass), host, port, password + ) + forked_daapd_updater = ForkedDaapdUpdater(hass, forked_daapd_api, entry.entry_id) + if not hass.data.get(DOMAIN): + hass.data[DOMAIN] = {entry.entry_id: {}} + hass.data.setdefault(DOMAIN, {}).setdefault(entry.entry_id, {})[ + HASS_DATA_UPDATER_KEY + ] = forked_daapd_updater await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True diff --git a/homeassistant/components/forked_daapd/coordinator.py b/homeassistant/components/forked_daapd/coordinator.py index 2db0a75c429..246ad1caa7d 100644 --- a/homeassistant/components/forked_daapd/coordinator.py +++ b/homeassistant/components/forked_daapd/coordinator.py @@ -39,6 +39,11 @@ class ForkedDaapdUpdater: self._all_output_ids: set[str] = set() self._entry_id = entry_id + @property + def api(self) -> ForkedDaapdAPI: + """Return the API object.""" + return self._api + async def async_init(self) -> None: """Perform async portion of class initialization.""" if not (server_config := await self._api.get_request("config")): diff --git a/homeassistant/components/forked_daapd/media_player.py b/homeassistant/components/forked_daapd/media_player.py index 8cbf33460aa..90a04dbc177 100644 --- a/homeassistant/components/forked_daapd/media_player.py +++ b/homeassistant/components/forked_daapd/media_player.py @@ -7,7 +7,6 @@ from collections import defaultdict import logging from typing import Any -from pyforked_daapd import ForkedDaapdAPI from pylibrespot_java import LibrespotJavaAPI from homeassistant.components import media_source @@ -29,7 +28,7 @@ from homeassistant.components.spotify import ( spotify_uri_from_media_browser_url, ) from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT +from homeassistant.const import CONF_HOST from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.dispatcher import ( @@ -85,12 +84,12 @@ async def async_setup_entry( async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up forked-daapd from a config entry.""" + forked_daapd_updater: ForkedDaapdUpdater = hass.data[DOMAIN][config_entry.entry_id][ + HASS_DATA_UPDATER_KEY + ] + host: str = config_entry.data[CONF_HOST] - port: int = config_entry.data[CONF_PORT] - password: str = config_entry.data[CONF_PASSWORD] - forked_daapd_api = ForkedDaapdAPI( - async_get_clientsession(hass), host, port, password - ) + forked_daapd_api = forked_daapd_updater.api forked_daapd_master = ForkedDaapdMaster( clientsession=async_get_clientsession(hass), api=forked_daapd_api, @@ -111,16 +110,8 @@ async def async_setup_entry( ) config_entry.async_on_unload(config_entry.add_update_listener(update_listener)) - if not hass.data.get(DOMAIN): - hass.data[DOMAIN] = {config_entry.entry_id: {}} - async_add_entities([forked_daapd_master], False) - forked_daapd_updater = ForkedDaapdUpdater( - hass, forked_daapd_api, config_entry.entry_id - ) - hass.data[DOMAIN][config_entry.entry_id][HASS_DATA_UPDATER_KEY] = ( - forked_daapd_updater - ) + await forked_daapd_updater.async_init() diff --git a/tests/components/forked_daapd/test_browse_media.py b/tests/components/forked_daapd/test_browse_media.py index cbd278128ae..88b29c2bbba 100644 --- a/tests/components/forked_daapd/test_browse_media.py +++ b/tests/components/forked_daapd/test_browse_media.py @@ -34,7 +34,7 @@ async def test_async_browse_media( await hass.async_block_till_done() with patch( - "homeassistant.components.forked_daapd.media_player.ForkedDaapdAPI", + "homeassistant.components.forked_daapd.ForkedDaapdAPI", autospec=True, ) as mock_api: mock_api.return_value.get_request.return_value = {"websocket_port": 2} @@ -214,7 +214,7 @@ async def test_async_browse_media_not_found( await hass.async_block_till_done() with patch( - "homeassistant.components.forked_daapd.media_player.ForkedDaapdAPI", + "homeassistant.components.forked_daapd.ForkedDaapdAPI", autospec=True, ) as mock_api: mock_api.return_value.get_request.return_value = {"websocket_port": 2} @@ -375,7 +375,7 @@ async def test_async_browse_image( """Test browse media images.""" with patch( - "homeassistant.components.forked_daapd.media_player.ForkedDaapdAPI", + "homeassistant.components.forked_daapd.ForkedDaapdAPI", autospec=True, ) as mock_api: mock_api.return_value.get_request.return_value = {"websocket_port": 2} @@ -430,7 +430,7 @@ async def test_async_browse_image_missing( """Test browse media images with no image available.""" with patch( - "homeassistant.components.forked_daapd.media_player.ForkedDaapdAPI", + "homeassistant.components.forked_daapd.ForkedDaapdAPI", autospec=True, ) as mock_api: mock_api.return_value.get_request.return_value = {"websocket_port": 2} diff --git a/tests/components/forked_daapd/test_config_flow.py b/tests/components/forked_daapd/test_config_flow.py index 8bf5de31da2..ba1f0e6c227 100644 --- a/tests/components/forked_daapd/test_config_flow.py +++ b/tests/components/forked_daapd/test_config_flow.py @@ -1,7 +1,7 @@ """The config flow tests for the forked_daapd media player platform.""" from ipaddress import ip_address -from unittest.mock import AsyncMock, MagicMock, patch +from unittest.mock import AsyncMock, patch import pytest @@ -12,12 +12,10 @@ from homeassistant.components.forked_daapd.const import ( CONF_TTS_VOLUME, DOMAIN, ) -from homeassistant.components.forked_daapd.media_player import async_setup_entry -from homeassistant.config_entries import SOURCE_USER, SOURCE_ZEROCONF +from homeassistant.config_entries import SOURCE_USER, SOURCE_ZEROCONF, ConfigEntryState from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType -from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo from tests.common import MockConfigEntry @@ -75,7 +73,7 @@ async def test_config_flow(hass: HomeAssistant, config_entry: MockConfigEntry) - new=AsyncMock(), ) as mock_test_connection, patch( - "homeassistant.components.forked_daapd.media_player.ForkedDaapdAPI.get_request", + "homeassistant.components.forked_daapd.ForkedDaapdAPI.get_request", autospec=True, ) as mock_get_request, ): @@ -232,7 +230,7 @@ async def test_options_flow(hass: HomeAssistant, config_entry: MockConfigEntry) """Test config flow options.""" with patch( - "homeassistant.components.forked_daapd.media_player.ForkedDaapdAPI.get_request", + "homeassistant.components.forked_daapd.ForkedDaapdAPI.get_request", autospec=True, ) as mock_get_request: mock_get_request.return_value = SAMPLE_CONFIG @@ -256,17 +254,18 @@ async def test_options_flow(hass: HomeAssistant, config_entry: MockConfigEntry) async def test_async_setup_entry_not_ready( - hass: HomeAssistant, config_entry: MockConfigEntry + hass: HomeAssistant, config_entry: MockConfigEntry, caplog: pytest.LogCaptureFixture ) -> None: """Test that a PlatformNotReady exception is thrown during platform setup.""" with patch( - "homeassistant.components.forked_daapd.media_player.ForkedDaapdAPI", + "homeassistant.components.forked_daapd.ForkedDaapdAPI", autospec=True, ) as mock_api: mock_api.return_value.get_request.return_value = None config_entry.add_to_hass(hass) - with pytest.raises(PlatformNotReady): - await async_setup_entry(hass, config_entry, MagicMock()) + await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() mock_api.return_value.get_request.assert_called_once() + assert "Platform forked_daapd not ready yet" in caplog.text + assert config_entry.state is ConfigEntryState.LOADED diff --git a/tests/components/forked_daapd/test_media_player.py b/tests/components/forked_daapd/test_media_player.py index 6d7d267eb63..8f0105d48d7 100644 --- a/tests/components/forked_daapd/test_media_player.py +++ b/tests/components/forked_daapd/test_media_player.py @@ -313,7 +313,7 @@ async def mock_api_object_fixture( return get_request_return_values[update_type] with patch( - "homeassistant.components.forked_daapd.media_player.ForkedDaapdAPI", + "homeassistant.components.forked_daapd.ForkedDaapdAPI", autospec=True, ) as mock_api: mock_api.return_value.get_request.side_effect = get_request_side_effect @@ -808,7 +808,7 @@ async def test_invalid_websocket_port( ) -> None: """Test invalid websocket port on async_init.""" with patch( - "homeassistant.components.forked_daapd.media_player.ForkedDaapdAPI", + "homeassistant.components.forked_daapd.ForkedDaapdAPI", autospec=True, ) as mock_api: mock_api.return_value.get_request.return_value = SAMPLE_CONFIG_NO_WEBSOCKET