From 67a14d04632d76b5c733886ca552dbc79ebd69b9 Mon Sep 17 00:00:00 2001 From: Ingmar Delsink Date: Thu, 21 Mar 2024 11:05:36 +0100 Subject: [PATCH] Add transmission-integration path and protocol (#104334) This updates the config_flow migration from v1.1 to v1.2 including migration tests --- .../components/transmission/__init__.py | 37 +++++++++++++++++++ .../components/transmission/config_flow.py | 14 ++++++- .../components/transmission/const.py | 2 + .../components/transmission/strings.json | 9 ++++- tests/components/transmission/__init__.py | 12 +++++- .../transmission/test_config_flow.py | 5 +-- tests/components/transmission/test_init.py | 30 ++++++++++++++- 7 files changed, 99 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/transmission/__init__.py b/homeassistant/components/transmission/__init__.py index bbf4bf5d630..4dcc4d41950 100644 --- a/homeassistant/components/transmission/__init__.py +++ b/homeassistant/components/transmission/__init__.py @@ -21,7 +21,9 @@ from homeassistant.const import ( CONF_ID, CONF_NAME, CONF_PASSWORD, + CONF_PATH, CONF_PORT, + CONF_SSL, CONF_USERNAME, Platform, ) @@ -38,6 +40,8 @@ from .const import ( ATTR_TORRENT, CONF_ENTRY_ID, DEFAULT_DELETE_DATA, + DEFAULT_PATH, + DEFAULT_SSL, DOMAIN, SERVICE_ADD_TORRENT, SERVICE_REMOVE_TORRENT, @@ -211,12 +215,43 @@ async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> return unload_ok +async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: + """Migrate an old config entry.""" + _LOGGER.debug( + "Migrating from version %s.%s", + config_entry.version, + config_entry.minor_version, + ) + + if config_entry.version == 1: + # Version 1.2 adds ssl and path + if config_entry.minor_version < 2: + new = {**config_entry.data} + + new[CONF_PATH] = DEFAULT_PATH + new[CONF_SSL] = DEFAULT_SSL + + hass.config_entries.async_update_entry( + config_entry, data=new, version=1, minor_version=2 + ) + + _LOGGER.debug( + "Migration to version %s.%s successful", + config_entry.version, + config_entry.minor_version, + ) + + return True + + async def get_api( hass: HomeAssistant, entry: dict[str, Any] ) -> transmission_rpc.Client: """Get Transmission client.""" + protocol = "https" if entry[CONF_SSL] else "http" host = entry[CONF_HOST] port = entry[CONF_PORT] + path = entry[CONF_PATH] username = entry.get(CONF_USERNAME) password = entry.get(CONF_PASSWORD) @@ -226,8 +261,10 @@ async def get_api( transmission_rpc.Client, username=username, password=password, + protocol=protocol, host=host, port=port, + path=path, ) ) _LOGGER.debug("Successfully connected to %s", host) diff --git a/homeassistant/components/transmission/config_flow.py b/homeassistant/components/transmission/config_flow.py index de3616646bf..62879d2d0af 100644 --- a/homeassistant/components/transmission/config_flow.py +++ b/homeassistant/components/transmission/config_flow.py @@ -13,7 +13,14 @@ from homeassistant.config_entries import ( ConfigFlowResult, OptionsFlow, ) -from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME +from homeassistant.const import ( + CONF_HOST, + CONF_PASSWORD, + CONF_PATH, + CONF_PORT, + CONF_SSL, + CONF_USERNAME, +) from homeassistant.core import callback from . import get_api @@ -23,7 +30,9 @@ from .const import ( DEFAULT_LIMIT, DEFAULT_NAME, DEFAULT_ORDER, + DEFAULT_PATH, DEFAULT_PORT, + DEFAULT_SSL, DOMAIN, SUPPORTED_ORDER_MODES, ) @@ -31,7 +40,9 @@ from .errors import AuthenticationError, CannotConnect, UnknownError DATA_SCHEMA = vol.Schema( { + vol.Optional(CONF_SSL, default=DEFAULT_SSL): bool, vol.Required(CONF_HOST): str, + vol.Required(CONF_PATH, default=DEFAULT_PATH): str, vol.Optional(CONF_USERNAME): str, vol.Optional(CONF_PASSWORD): str, vol.Required(CONF_PORT, default=DEFAULT_PORT): int, @@ -43,6 +54,7 @@ class TransmissionFlowHandler(ConfigFlow, domain=DOMAIN): """Handle Tansmission config flow.""" VERSION = 1 + MINOR_VERSION = 2 _reauth_entry: ConfigEntry | None @staticmethod diff --git a/homeassistant/components/transmission/const.py b/homeassistant/components/transmission/const.py index 98f9184f1af..0dd77fa6aa3 100644 --- a/homeassistant/components/transmission/const.py +++ b/homeassistant/components/transmission/const.py @@ -31,7 +31,9 @@ DEFAULT_DELETE_DATA = False DEFAULT_LIMIT = 10 DEFAULT_ORDER = ORDER_OLDEST_FIRST DEFAULT_NAME = "Transmission" +DEFAULT_SSL = False DEFAULT_PORT = 9091 +DEFAULT_PATH = "/transmission/rpc" DEFAULT_SCAN_INTERVAL = 120 STATE_ATTR_TORRENT_INFO = "torrent_info" diff --git a/homeassistant/components/transmission/strings.json b/homeassistant/components/transmission/strings.json index 8a73eb90829..20ae6ca723d 100644 --- a/homeassistant/components/transmission/strings.json +++ b/homeassistant/components/transmission/strings.json @@ -5,9 +5,14 @@ "title": "Set up Transmission Client", "data": { "host": "[%key:common::config_flow::data::host%]", - "username": "[%key:common::config_flow::data::username%]", "password": "[%key:common::config_flow::data::password%]", - "port": "[%key:common::config_flow::data::port%]" + "path": "[%key:common::config_flow::data::path%]", + "port": "[%key:common::config_flow::data::port%]", + "ssl": "[%key:common::config_flow::data::ssl%]", + "username": "[%key:common::config_flow::data::username%]" + }, + "data_description": { + "path": "The RPC request target path. E.g. `/transmission/rpc`" } }, "reauth_confirm": { diff --git a/tests/components/transmission/__init__.py b/tests/components/transmission/__init__.py index e371a3691a2..c4abba7b832 100644 --- a/tests/components/transmission/__init__.py +++ b/tests/components/transmission/__init__.py @@ -7,7 +7,17 @@ OLD_MOCK_CONFIG_DATA = { "password": "pass", "port": 9091, } -MOCK_CONFIG_DATA = { + +MOCK_CONFIG_DATA_VERSION_1_1 = { + "host": "0.0.0.0", + "username": "user", + "password": "pass", + "port": 9091, +} + +MOCK_CONFIG_DATA = { + "ssl": False, + "path": "/transmission/rpc", "host": "0.0.0.0", "username": "user", "password": "pass", diff --git a/tests/components/transmission/test_config_flow.py b/tests/components/transmission/test_config_flow.py index 451d3ec8b78..0e184ffc96b 100644 --- a/tests/components/transmission/test_config_flow.py +++ b/tests/components/transmission/test_config_flow.py @@ -157,10 +157,7 @@ async def test_error_on_connection_failure( async def test_reauth_success(hass: HomeAssistant) -> None: """Test we can reauth.""" - entry = MockConfigEntry( - domain=transmission.DOMAIN, - data=MOCK_CONFIG_DATA, - ) + entry = MockConfigEntry(domain=transmission.DOMAIN, data=MOCK_CONFIG_DATA) entry.add_to_hass(hass) result = await hass.config_entries.flow.async_init( diff --git a/tests/components/transmission/test_init.py b/tests/components/transmission/test_init.py index 63b7ac154ed..7efbaad76fb 100644 --- a/tests/components/transmission/test_init.py +++ b/tests/components/transmission/test_init.py @@ -11,12 +11,17 @@ from transmission_rpc.error import ( from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN -from homeassistant.components.transmission.const import DOMAIN +from homeassistant.components.transmission.const import ( + DEFAULT_PATH, + DEFAULT_SSL, + DOMAIN, +) from homeassistant.config_entries import ConfigEntryState +from homeassistant.const import CONF_PATH, CONF_SSL from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er -from . import MOCK_CONFIG_DATA, OLD_MOCK_CONFIG_DATA +from . import MOCK_CONFIG_DATA, MOCK_CONFIG_DATA_VERSION_1_1, OLD_MOCK_CONFIG_DATA from tests.common import MockConfigEntry @@ -39,6 +44,27 @@ async def test_successful_config_entry(hass: HomeAssistant) -> None: assert entry.state == ConfigEntryState.LOADED +async def test_config_flow_entry_migrate_1_1_to_1_2(hass: HomeAssistant) -> None: + """Test that config flow entry is migrated correctly from v1.1 to v1.2.""" + entry = MockConfigEntry( + domain=DOMAIN, + data=MOCK_CONFIG_DATA_VERSION_1_1, + version=1, + minor_version=1, + ) + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + # Test that config entry is at the current version. + assert entry.version == 1 + assert entry.minor_version == 2 + + assert entry.data[CONF_SSL] == DEFAULT_SSL + assert entry.data[CONF_PATH] == DEFAULT_PATH + + async def test_setup_failed_connection_error( hass: HomeAssistant, mock_api: MagicMock ) -> None: