From a8cd7203dfa73104bdcb67cfa61ef683febbb7ff Mon Sep 17 00:00:00 2001 From: Quentame Date: Wed, 22 Apr 2020 23:28:47 +0200 Subject: [PATCH] Bump python-synology to 0.7.0 (#34534) --- .../components/synology_dsm/__init__.py | 12 +--- .../components/synology_dsm/config_flow.py | 42 ++++--------- .../components/synology_dsm/const.py | 1 - .../components/synology_dsm/manifest.json | 2 +- .../components/synology_dsm/strings.json | 6 +- .../synology_dsm/translations/en.json | 6 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- .../synology_dsm/test_config_flow.py | 60 ++++++++++++------- 9 files changed, 62 insertions(+), 71 deletions(-) diff --git a/homeassistant/components/synology_dsm/__init__.py b/homeassistant/components/synology_dsm/__init__.py index f2fd3d3af0c..3fbed6955d9 100644 --- a/homeassistant/components/synology_dsm/__init__.py +++ b/homeassistant/components/synology_dsm/__init__.py @@ -9,7 +9,6 @@ import voluptuous as vol from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import ( - CONF_API_VERSION, CONF_DISKS, CONF_HOST, CONF_PASSWORD, @@ -22,14 +21,13 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.typing import HomeAssistantType -from .const import CONF_VOLUMES, DEFAULT_DSM_VERSION, DEFAULT_SSL, DOMAIN +from .const import CONF_VOLUMES, DEFAULT_SSL, DOMAIN CONFIG_SCHEMA = vol.Schema( { vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_PORT): cv.port, vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean, - vol.Optional(CONF_API_VERSION, default=DEFAULT_DSM_VERSION): cv.positive_int, vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, vol.Optional(CONF_DISKS): cv.ensure_list, @@ -70,12 +68,9 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): password = entry.data[CONF_PASSWORD] unit = hass.config.units.temperature_unit use_ssl = entry.data[CONF_SSL] - api_version = entry.data.get(CONF_API_VERSION, DEFAULT_DSM_VERSION) device_token = entry.data.get("device_token") - api = SynoApi( - hass, host, port, username, password, unit, use_ssl, device_token, api_version - ) + api = SynoApi(hass, host, port, username, password, unit, use_ssl, device_token) await api.async_setup() @@ -109,7 +104,6 @@ class SynoApi: temp_unit: str, use_ssl: bool, device_token: str, - api_version: int, ): """Initialize the API wrapper class.""" self._hass = hass @@ -119,7 +113,6 @@ class SynoApi: self._password = password self._use_ssl = use_ssl self._device_token = device_token - self._api_version = api_version self.temp_unit = temp_unit self._dsm: SynologyDSM = None @@ -143,7 +136,6 @@ class SynoApi: self._password, self._use_ssl, device_token=self._device_token, - dsm_version=self._api_version, ) await self._hass.async_add_executor_job(self._fetch_device_configuration) diff --git a/homeassistant/components/synology_dsm/config_flow.py b/homeassistant/components/synology_dsm/config_flow.py index c478270f8b0..c1e8cf553d9 100644 --- a/homeassistant/components/synology_dsm/config_flow.py +++ b/homeassistant/components/synology_dsm/config_flow.py @@ -4,16 +4,17 @@ from urllib.parse import urlparse from synology_dsm import SynologyDSM from synology_dsm.exceptions import ( + SynologyDSMException, SynologyDSMLogin2SAFailedException, SynologyDSMLogin2SARequiredException, SynologyDSMLoginInvalidException, + SynologyDSMRequestException, ) import voluptuous as vol from homeassistant import config_entries, exceptions from homeassistant.components import ssdp from homeassistant.const import ( - CONF_API_VERSION, CONF_DISKS, CONF_HOST, CONF_NAME, @@ -23,13 +24,7 @@ from homeassistant.const import ( CONF_USERNAME, ) -from .const import ( - CONF_VOLUMES, - DEFAULT_DSM_VERSION, - DEFAULT_PORT, - DEFAULT_PORT_SSL, - DEFAULT_SSL, -) +from .const import CONF_VOLUMES, DEFAULT_PORT, DEFAULT_PORT_SSL, DEFAULT_SSL from .const import DOMAIN # pylint: disable=unused-import _LOGGER = logging.getLogger(__name__) @@ -56,12 +51,6 @@ def _ordered_shared_schema(schema_input): vol.Required(CONF_PASSWORD, default=schema_input.get(CONF_PASSWORD, "")): str, vol.Optional(CONF_PORT, default=schema_input.get(CONF_PORT, "")): str, vol.Optional(CONF_SSL, default=schema_input.get(CONF_SSL, DEFAULT_SSL)): bool, - vol.Optional( - CONF_API_VERSION, - default=schema_input.get(CONF_API_VERSION, DEFAULT_DSM_VERSION), - ): vol.All( - vol.Coerce(int), vol.In([5, 6]), # DSM versions supported by the library - ), } @@ -111,7 +100,6 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): username = user_input[CONF_USERNAME] password = user_input[CONF_PASSWORD] use_ssl = user_input.get(CONF_SSL, DEFAULT_SSL) - api_version = user_input.get(CONF_API_VERSION, DEFAULT_DSM_VERSION) otp_code = user_input.get(CONF_OTP_CODE) if not port: @@ -120,9 +108,7 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): else: port = DEFAULT_PORT - api = SynologyDSM( - host, port, username, password, use_ssl, dsm_version=api_version, - ) + api = SynologyDSM(host, port, username, password, use_ssl) try: serial = await self.hass.async_add_executor_job( @@ -134,8 +120,12 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): errors[CONF_OTP_CODE] = "otp_failed" user_input[CONF_OTP_CODE] = None return await self.async_step_2sa(user_input, errors) - except (SynologyDSMLoginInvalidException, InvalidAuth): + except SynologyDSMLoginInvalidException: errors[CONF_USERNAME] = "login" + except SynologyDSMRequestException: + errors[CONF_HOST] = "connection" + except SynologyDSMException: + errors["base"] = "unknown" except InvalidData: errors["base"] = "missing_data" @@ -152,7 +142,6 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): CONF_SSL: use_ssl, CONF_USERNAME: username, CONF_PASSWORD: password, - CONF_API_VERSION: api_version, } if otp_code: config_data["device_token"] = api.device_token @@ -216,28 +205,21 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): def _login_and_fetch_syno_info(api, otp_code): """Login to the NAS and fetch basic data.""" - if not api.login(otp_code): - raise InvalidAuth - # These do i/o - information = api.information + api.login(otp_code) utilisation = api.utilisation storage = api.storage if ( - information.serial is None + api.information.serial is None or utilisation.cpu_user_load is None or storage.disks_ids is None or storage.volumes_ids is None ): raise InvalidData - return information.serial + return api.information.serial class InvalidData(exceptions.HomeAssistantError): """Error to indicate we get invalid data from the nas.""" - - -class InvalidAuth(exceptions.HomeAssistantError): - """Error to indicate there is invalid auth.""" diff --git a/homeassistant/components/synology_dsm/const.py b/homeassistant/components/synology_dsm/const.py index c0b1fe782c4..8c17de5e997 100644 --- a/homeassistant/components/synology_dsm/const.py +++ b/homeassistant/components/synology_dsm/const.py @@ -12,7 +12,6 @@ CONF_VOLUMES = "volumes" DEFAULT_SSL = True DEFAULT_PORT = 5000 DEFAULT_PORT_SSL = 5001 -DEFAULT_DSM_VERSION = 6 UTILISATION_SENSORS = { "cpu_other_load": ["CPU Load (Other)", UNIT_PERCENTAGE, "mdi:chip"], diff --git a/homeassistant/components/synology_dsm/manifest.json b/homeassistant/components/synology_dsm/manifest.json index b54132c6897..c7abd809b87 100644 --- a/homeassistant/components/synology_dsm/manifest.json +++ b/homeassistant/components/synology_dsm/manifest.json @@ -2,7 +2,7 @@ "domain": "synology_dsm", "name": "Synology DSM", "documentation": "https://www.home-assistant.io/integrations/synology_dsm", - "requirements": ["python-synology==0.6.0"], + "requirements": ["python-synology==0.7.0"], "codeowners": ["@ProtoThis", "@Quentame"], "config_flow": true, "ssdp": [ diff --git a/homeassistant/components/synology_dsm/strings.json b/homeassistant/components/synology_dsm/strings.json index b90fd52fe5f..d00525f995d 100644 --- a/homeassistant/components/synology_dsm/strings.json +++ b/homeassistant/components/synology_dsm/strings.json @@ -8,7 +8,6 @@ "host": "Host", "port": "Port (Optional)", "ssl": "Use SSL/TLS to connect to your NAS", - "api_version": "DSM version", "username": "Username", "password": "Password" } @@ -24,7 +23,6 @@ "description": "Do you want to setup {name} ({host})?", "data": { "ssl": "Use SSL/TLS to connect to your NAS", - "api_version": "DSM version", "username": "Username", "password": "Password", "port": "Port (Optional)" @@ -32,9 +30,11 @@ } }, "error": { + "connection": "Connection error: please check your host, password & ssl", "login": "Login error: please check your username & password", "missing_data": "Missing data: please retry later or an other configuration", - "otp_failed": "Two-step authentication failed, retry with a new pass code" + "otp_failed": "Two-step authentication failed, retry with a new pass code", + "unknown": "Unknown error: please check logs to get more details" }, "abort": { "already_configured": "Host already configured" } } diff --git a/homeassistant/components/synology_dsm/translations/en.json b/homeassistant/components/synology_dsm/translations/en.json index 57ee3455840..41814a1e68d 100644 --- a/homeassistant/components/synology_dsm/translations/en.json +++ b/homeassistant/components/synology_dsm/translations/en.json @@ -4,9 +4,11 @@ "already_configured": "Host already configured" }, "error": { + "connection": "Connection error: please check your host, password & ssl", "login": "Login error: please check your username & password", "missing_data": "Missing data: please retry later or an other configuration", - "otp_failed": "Two-step authentication failed, retry with a new pass code" + "otp_failed": "Two-step authentication failed, retry with a new pass code", + "unknown": "Unknown error: please check logs to get more details" }, "flow_title": "Synology DSM {name} ({host})", "step": { @@ -18,7 +20,6 @@ }, "link": { "data": { - "api_version": "DSM version", "password": "Password", "port": "Port (Optional)", "ssl": "Use SSL/TLS to connect to your NAS", @@ -29,7 +30,6 @@ }, "user": { "data": { - "api_version": "DSM version", "host": "Host", "password": "Password", "port": "Port (Optional)", diff --git a/requirements_all.txt b/requirements_all.txt index e9a44259aec..8c89391d060 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1680,7 +1680,7 @@ python-sochain-api==0.0.2 python-songpal==0.11.2 # homeassistant.components.synology_dsm -python-synology==0.6.0 +python-synology==0.7.0 # homeassistant.components.tado python-tado==0.8.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 80d318cf0b6..77c12ead2c7 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -650,7 +650,7 @@ python-miio==0.5.0.1 python-nest==4.1.0 # homeassistant.components.synology_dsm -python-synology==0.6.0 +python-synology==0.7.0 # homeassistant.components.tado python-tado==0.8.1 diff --git a/tests/components/synology_dsm/test_config_flow.py b/tests/components/synology_dsm/test_config_flow.py index 17b98b7c910..9a9283256c5 100644 --- a/tests/components/synology_dsm/test_config_flow.py +++ b/tests/components/synology_dsm/test_config_flow.py @@ -4,8 +4,11 @@ from unittest.mock import MagicMock, Mock, patch import pytest from synology_dsm.exceptions import ( + SynologyDSMException, SynologyDSMLogin2SAFailedException, SynologyDSMLogin2SARequiredException, + SynologyDSMLoginInvalidException, + SynologyDSMRequestException, ) from homeassistant import data_entry_flow, setup @@ -13,7 +16,6 @@ from homeassistant.components import ssdp from homeassistant.components.synology_dsm.config_flow import CONF_OTP_CODE from homeassistant.components.synology_dsm.const import ( CONF_VOLUMES, - DEFAULT_DSM_VERSION, DEFAULT_PORT, DEFAULT_PORT_SSL, DEFAULT_SSL, @@ -21,7 +23,6 @@ from homeassistant.components.synology_dsm.const import ( ) from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_SSDP, SOURCE_USER from homeassistant.const import ( - CONF_API_VERSION, CONF_DISKS, CONF_HOST, CONF_PASSWORD, @@ -76,16 +77,6 @@ def mock_controller_service_2sa(): yield service_mock -@pytest.fixture(name="service_login_failed") -def mock_controller_service_login_failed(): - """Mock a failed login.""" - with patch( - "homeassistant.components.synology_dsm.config_flow.SynologyDSM" - ) as service_mock: - service_mock.return_value.login = Mock(return_value=False) - yield service_mock - - @pytest.fixture(name="service_failed") def mock_controller_service_failed(): """Mock a failed service.""" @@ -117,7 +108,6 @@ async def test_user(hass: HomeAssistantType, service: MagicMock): CONF_SSL: SSL, CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD, - CONF_API_VERSION: 5, }, ) assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY @@ -128,7 +118,6 @@ async def test_user(hass: HomeAssistantType, service: MagicMock): assert result["data"][CONF_SSL] == SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD - assert result["data"][CONF_API_VERSION] == 5 assert result["data"].get("device_token") is None assert result["data"].get(CONF_DISKS) is None assert result["data"].get(CONF_VOLUMES) is None @@ -153,7 +142,6 @@ async def test_user(hass: HomeAssistantType, service: MagicMock): assert not result["data"][CONF_SSL] assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD - assert result["data"][CONF_API_VERSION] == DEFAULT_DSM_VERSION assert result["data"].get("device_token") is None assert result["data"].get(CONF_DISKS) is None assert result["data"].get(CONF_VOLUMES) is None @@ -216,7 +204,6 @@ async def test_import(hass: HomeAssistantType, service: MagicMock): assert result["data"][CONF_SSL] == DEFAULT_SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD - assert result["data"][CONF_API_VERSION] == DEFAULT_DSM_VERSION assert result["data"].get("device_token") is None assert result["data"].get(CONF_DISKS) is None assert result["data"].get(CONF_VOLUMES) is None @@ -232,7 +219,6 @@ async def test_import(hass: HomeAssistantType, service: MagicMock): CONF_SSL: SSL, CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD, - CONF_API_VERSION: 5, CONF_DISKS: ["sda", "sdb", "sdc"], CONF_VOLUMES: ["volume_1"], }, @@ -245,7 +231,6 @@ async def test_import(hass: HomeAssistantType, service: MagicMock): assert result["data"][CONF_SSL] == SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD - assert result["data"][CONF_API_VERSION] == 5 assert result["data"].get("device_token") is None assert result["data"][CONF_DISKS] == ["sda", "sdb", "sdc"] assert result["data"][CONF_VOLUMES] == ["volume_1"] @@ -278,8 +263,12 @@ async def test_abort_if_already_setup(hass: HomeAssistantType, service: MagicMoc assert result["reason"] == "already_configured" -async def test_login_failed(hass: HomeAssistantType, service_login_failed: MagicMock): - """Test when we have errors during connection.""" +async def test_login_failed(hass: HomeAssistantType, service: MagicMock): + """Test when we have errors during login.""" + service.return_value.login = Mock( + side_effect=(SynologyDSMLoginInvalidException(USERNAME)) + ) + result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, @@ -289,6 +278,36 @@ async def test_login_failed(hass: HomeAssistantType, service_login_failed: Magic assert result["errors"] == {CONF_USERNAME: "login"} +async def test_connection_failed(hass: HomeAssistantType, service: MagicMock): + """Test when we have errors during connection.""" + service.return_value.login = Mock( + side_effect=SynologyDSMRequestException(IOError("arg")) + ) + + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data={CONF_HOST: HOST, CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["errors"] == {CONF_HOST: "connection"} + + +async def test_unknown_failed(hass: HomeAssistantType, service: MagicMock): + """Test when we have an unknown error.""" + service.return_value.login = Mock(side_effect=SynologyDSMException) + + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data={CONF_HOST: HOST, CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["errors"] == {"base": "unknown"} + + async def test_missing_data_after_login( hass: HomeAssistantType, service_failed: MagicMock ): @@ -329,7 +348,6 @@ async def test_form_ssdp(hass: HomeAssistantType, service: MagicMock): assert result["data"][CONF_SSL] == DEFAULT_SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD - assert result["data"][CONF_API_VERSION] == DEFAULT_DSM_VERSION assert result["data"].get("device_token") is None assert result["data"].get(CONF_DISKS) is None assert result["data"].get(CONF_VOLUMES) is None