From a8b8b245d1059d710da2c409785e2aaa5944a5ba Mon Sep 17 00:00:00 2001 From: Robert Hillis Date: Mon, 26 Sep 2022 08:54:17 -0400 Subject: [PATCH] Allow multiple entries in Tautulli (#74406) --- homeassistant/components/tautulli/__init__.py | 4 +- .../components/tautulli/config_flow.py | 3 +- homeassistant/components/tautulli/sensor.py | 2 +- .../components/tautulli/strings.json | 2 +- .../components/tautulli/translations/en.json | 2 +- tests/components/tautulli/__init__.py | 24 +------ tests/components/tautulli/test_config_flow.py | 69 ++++++++++++------- 7 files changed, 53 insertions(+), 53 deletions(-) diff --git a/homeassistant/components/tautulli/__init__.py b/homeassistant/components/tautulli/__init__.py index bd5032014bc..a90d78380b4 100644 --- a/homeassistant/components/tautulli/__init__.py +++ b/homeassistant/components/tautulli/__init__.py @@ -30,7 +30,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: ) coordinator = TautulliDataUpdateCoordinator(hass, host_configuration, api_client) await coordinator.async_config_entry_first_refresh() - hass.data[DOMAIN] = coordinator + hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True @@ -39,7 +39,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): - hass.data.pop(DOMAIN) + hass.data[DOMAIN].pop(entry.entry_id) return unload_ok diff --git a/homeassistant/components/tautulli/config_flow.py b/homeassistant/components/tautulli/config_flow.py index f06405825c9..532852687da 100644 --- a/homeassistant/components/tautulli/config_flow.py +++ b/homeassistant/components/tautulli/config_flow.py @@ -24,10 +24,9 @@ class TautulliConfigFlow(ConfigFlow, domain=DOMAIN): self, user_input: dict[str, Any] | None = None ) -> FlowResult: """Handle a flow initiated by the user.""" - if self._async_current_entries(): - return self.async_abort(reason="single_instance_allowed") errors = {} if user_input is not None: + self._async_abort_entries_match({CONF_URL: user_input[CONF_URL]}) if (error := await self.validate_input(user_input)) is None: return self.async_create_entry( title=DEFAULT_NAME, diff --git a/homeassistant/components/tautulli/sensor.py b/homeassistant/components/tautulli/sensor.py index 5653aa5dc57..7109199fdcd 100644 --- a/homeassistant/components/tautulli/sensor.py +++ b/homeassistant/components/tautulli/sensor.py @@ -232,7 +232,7 @@ async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: """Set up Tautulli sensor.""" - coordinator: TautulliDataUpdateCoordinator = hass.data[DOMAIN] + coordinator: TautulliDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] entities: list[TautulliSensor | TautulliSessionSensor] = [ TautulliSensor( coordinator, diff --git a/homeassistant/components/tautulli/strings.json b/homeassistant/components/tautulli/strings.json index 9b561ea6f5b..90c64a6a8d6 100644 --- a/homeassistant/components/tautulli/strings.json +++ b/homeassistant/components/tautulli/strings.json @@ -23,7 +23,7 @@ "unknown": "[%key:common::config_flow::error::unknown%]" }, "abort": { - "single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]", + "already_configured": "[%key:common::config_flow::abort::already_configured_service%]", "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]" } } diff --git a/homeassistant/components/tautulli/translations/en.json b/homeassistant/components/tautulli/translations/en.json index c24497cfbd9..078f02d7bcd 100644 --- a/homeassistant/components/tautulli/translations/en.json +++ b/homeassistant/components/tautulli/translations/en.json @@ -2,7 +2,7 @@ "config": { "abort": { "reauth_successful": "Re-authentication was successful", - "single_instance_allowed": "Already configured. Only a single configuration possible." + "already_configured": "Service is already configured" }, "error": { "cannot_connect": "Failed to connect", diff --git a/tests/components/tautulli/__init__.py b/tests/components/tautulli/__init__.py index f296830bef4..b48488c7216 100644 --- a/tests/components/tautulli/__init__.py +++ b/tests/components/tautulli/__init__.py @@ -2,14 +2,9 @@ from unittest.mock import AsyncMock, patch -from homeassistant.components.tautulli.const import CONF_MONITORED_USERS, DOMAIN +from homeassistant.components.tautulli.const import DOMAIN from homeassistant.const import ( CONF_API_KEY, - CONF_HOST, - CONF_MONITORED_CONDITIONS, - CONF_PATH, - CONF_PORT, - CONF_SSL, CONF_URL, CONF_VERIFY_SSL, CONTENT_TYPE_JSON, @@ -22,7 +17,6 @@ from tests.test_util.aiohttp import AiohttpClientMocker API_KEY = "abcd" URL = "http://1.2.3.4:8181/test" NAME = "Tautulli" -SSL = False VERIFY_SSL = True CONF_DATA = { @@ -30,19 +24,6 @@ CONF_DATA = { CONF_URL: URL, CONF_VERIFY_SSL: VERIFY_SSL, } -CONF_IMPORT_DATA = { - CONF_API_KEY: API_KEY, - CONF_HOST: "1.2.3.4", - CONF_MONITORED_CONDITIONS: ["Stream count"], - CONF_MONITORED_USERS: ["test"], - CONF_PORT: "8181", - CONF_PATH: "/test", - CONF_SSL: SSL, - CONF_VERIFY_SSL: VERIFY_SSL, -} - -DEFAULT_USERS = [{11111111: {"enabled": False}, 22222222: {"enabled": False}}] -SELECTED_USERNAMES = ["user1"] def patch_config_flow_tautulli(mocked_tautulli) -> AsyncMock: @@ -104,9 +85,6 @@ async def setup_integration( CONF_VERIFY_SSL: VERIFY_SSL, CONF_API_KEY: api_key, }, - options={ - CONF_MONITORED_USERS: DEFAULT_USERS, - }, ) entry.add_to_hass(hass) diff --git a/tests/components/tautulli/test_config_flow.py b/tests/components/tautulli/test_config_flow.py index d846f0915d0..d39f9c1e3a1 100644 --- a/tests/components/tautulli/test_config_flow.py +++ b/tests/components/tautulli/test_config_flow.py @@ -6,36 +6,15 @@ from pytautulli import exceptions from homeassistant import data_entry_flow from homeassistant.components.tautulli.const import DOMAIN from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_USER -from homeassistant.const import CONF_API_KEY, CONF_SOURCE +from homeassistant.const import CONF_API_KEY, CONF_SOURCE, CONF_URL, CONF_VERIFY_SSL from homeassistant.core import HomeAssistant -from . import ( - CONF_DATA, - CONF_IMPORT_DATA, - NAME, - patch_config_flow_tautulli, - setup_integration, -) +from . import CONF_DATA, NAME, patch_config_flow_tautulli, setup_integration from tests.common import MockConfigEntry from tests.test_util.aiohttp import AiohttpClientMocker -async def test_flow_user_single_instance_allowed(hass: HomeAssistant) -> None: - """Test user step single instance allowed.""" - entry = MockConfigEntry(domain=DOMAIN, data=CONF_DATA) - entry.add_to_hass(hass) - - with patch_config_flow_tautulli(AsyncMock()): - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_USER}, - data=CONF_IMPORT_DATA, - ) - assert result["type"] == data_entry_flow.FlowResultType.ABORT - assert result["reason"] == "single_instance_allowed" - - async def test_flow_user(hass: HomeAssistant) -> None: """Test user initiated flow.""" result = await hass.config_entries.flow.async_init( @@ -126,6 +105,50 @@ async def test_flow_user_unknown_error(hass: HomeAssistant) -> None: assert result2["data"] == CONF_DATA +async def test_flow_user_already_configured(hass: HomeAssistant) -> None: + """Test user step already configured.""" + entry = MockConfigEntry(domain=DOMAIN, data=CONF_DATA) + entry.add_to_hass(hass) + + with patch_config_flow_tautulli(AsyncMock()): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data=CONF_DATA, + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "already_configured" + + +async def test_flow_user_multiple_entries_allowed(hass: HomeAssistant) -> None: + """Test user step can configure multiple entries.""" + entry = MockConfigEntry(domain=DOMAIN, data=CONF_DATA) + entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={CONF_SOURCE: SOURCE_USER} + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["step_id"] == "user" + assert result["errors"] == {} + + input = { + CONF_URL: "http://1.2.3.5:8181/test", + CONF_API_KEY: "efgh", + CONF_VERIFY_SSL: True, + } + with patch_config_flow_tautulli(AsyncMock()): + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input=input, + ) + await hass.async_block_till_done() + + assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result2["title"] == NAME + assert result2["data"] == input + + async def test_flow_reauth( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker ) -> None: