diff --git a/homeassistant/components/pyload/config_flow.py b/homeassistant/components/pyload/config_flow.py index 3262069c2f5..a13dc1f9410 100644 --- a/homeassistant/components/pyload/config_flow.py +++ b/homeassistant/components/pyload/config_flow.py @@ -90,7 +90,7 @@ async def validate_input(hass: HomeAssistant, user_input: dict[str, Any]) -> Non password=user_input[CONF_PASSWORD], ) - await pyload.login() + await pyload.get_status() class PyLoadConfigFlow(ConfigFlow, domain=DOMAIN): diff --git a/homeassistant/components/pyload/coordinator.py b/homeassistant/components/pyload/coordinator.py index 7bb2b870520..a69ba0c67dd 100644 --- a/homeassistant/components/pyload/coordinator.py +++ b/homeassistant/components/pyload/coordinator.py @@ -64,19 +64,12 @@ class PyLoadCoordinator(DataUpdateCoordinator[PyLoadData]): **await self.pyload.get_status(), free_space=await self.pyload.free_space(), ) - except InvalidAuth: - try: - await self.pyload.login() - except InvalidAuth as exc: - raise ConfigEntryAuthFailed( - translation_domain=DOMAIN, - translation_key="setup_authentication_exception", - translation_placeholders={CONF_USERNAME: self.pyload.username}, - ) from exc - _LOGGER.debug( - "Unable to retrieve data due to cookie expiration, retrying after 20 seconds" - ) - return self.data + except InvalidAuth as e: + raise ConfigEntryAuthFailed( + translation_domain=DOMAIN, + translation_key="setup_authentication_exception", + translation_placeholders={CONF_USERNAME: self.pyload.username}, + ) from e except CannotConnect as e: raise UpdateFailed( translation_domain=DOMAIN, @@ -92,7 +85,6 @@ class PyLoadCoordinator(DataUpdateCoordinator[PyLoadData]): """Set up the coordinator.""" try: - await self.pyload.login() self.version = await self.pyload.version() except CannotConnect as e: raise ConfigEntryNotReady( diff --git a/homeassistant/components/pyload/manifest.json b/homeassistant/components/pyload/manifest.json index feaa23af7de..fe36327cc75 100644 --- a/homeassistant/components/pyload/manifest.json +++ b/homeassistant/components/pyload/manifest.json @@ -8,5 +8,5 @@ "iot_class": "local_polling", "loggers": ["pyloadapi"], "quality_scale": "platinum", - "requirements": ["PyLoadAPI==1.4.2"] + "requirements": ["PyLoadAPI==2.0.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index d9c4c700264..81c6d328e0c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -56,7 +56,7 @@ PyFlume==0.6.5 PyFronius==0.8.0 # homeassistant.components.pyload -PyLoadAPI==1.4.2 +PyLoadAPI==2.0.0 # homeassistant.components.met_eireann PyMetEireann==2024.11.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index e76480fddb8..e4cfa8c9110 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -56,7 +56,7 @@ PyFlume==0.6.5 PyFronius==0.8.0 # homeassistant.components.pyload -PyLoadAPI==1.4.2 +PyLoadAPI==2.0.0 # homeassistant.components.met_eireann PyMetEireann==2024.11.0 diff --git a/tests/components/pyload/conftest.py b/tests/components/pyload/conftest.py index 72fabfa3de1..d6895e02668 100644 --- a/tests/components/pyload/conftest.py +++ b/tests/components/pyload/conftest.py @@ -3,7 +3,7 @@ from collections.abc import Generator from unittest.mock import AsyncMock, MagicMock, patch -from pyloadapi.types import LoginResponse, StatusServerResponse +from pyloadapi.types import StatusServerResponse import pytest from homeassistant.components.pyload.const import DEFAULT_NAME, DOMAIN @@ -76,18 +76,6 @@ def mock_pyloadapi() -> Generator[MagicMock]: client = mock_client.return_value client.username = "username" client.api_url = "https://pyload.local:8000/" - client.login.return_value = LoginResponse( - { - "_permanent": True, - "authenticated": True, - "id": 2, - "name": "username", - "role": 0, - "perms": 0, - "template": "default", - "_flashes": [["message", "Logged in successfully"]], - } - ) client.get_status.return_value = StatusServerResponse( { diff --git a/tests/components/pyload/snapshots/test_sensor.ambr b/tests/components/pyload/snapshots/test_sensor.ambr index 4a83f01278d..1aea2675915 100644 --- a/tests/components/pyload/snapshots/test_sensor.ambr +++ b/tests/components/pyload/snapshots/test_sensor.ambr @@ -1,823 +1,4 @@ # serializer version: 1 -# name: test_sensor_update_exceptions[CannotConnect][sensor.pyload_active_downloads-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'state_class': , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_active_downloads', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Active downloads', - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Active downloads', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_active', - 'unit_of_measurement': 'downloads', - }) -# --- -# name: test_sensor_update_exceptions[CannotConnect][sensor.pyload_active_downloads-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'pyLoad Active downloads', - 'state_class': , - 'unit_of_measurement': 'downloads', - }), - 'context': , - 'entity_id': 'sensor.pyload_active_downloads', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unavailable', - }) -# --- -# name: test_sensor_update_exceptions[CannotConnect][sensor.pyload_downloads_in_queue-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'state_class': , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_downloads_in_queue', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Downloads in queue', - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Downloads in queue', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_queue', - 'unit_of_measurement': 'downloads', - }) -# --- -# name: test_sensor_update_exceptions[CannotConnect][sensor.pyload_downloads_in_queue-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'pyLoad Downloads in queue', - 'state_class': , - 'unit_of_measurement': 'downloads', - }), - 'context': , - 'entity_id': 'sensor.pyload_downloads_in_queue', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unavailable', - }) -# --- -# name: test_sensor_update_exceptions[CannotConnect][sensor.pyload_free_space-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_free_space', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Free space', - 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 1, - }), - 'sensor.private': dict({ - 'suggested_unit_of_measurement': , - }), - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Free space', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_free_space', - 'unit_of_measurement': , - }) -# --- -# name: test_sensor_update_exceptions[CannotConnect][sensor.pyload_free_space-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'data_size', - 'friendly_name': 'pyLoad Free space', - 'unit_of_measurement': , - }), - 'context': , - 'entity_id': 'sensor.pyload_free_space', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unavailable', - }) -# --- -# name: test_sensor_update_exceptions[CannotConnect][sensor.pyload_speed-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_speed', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Speed', - 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 1, - }), - 'sensor.private': dict({ - 'suggested_unit_of_measurement': , - }), - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Speed', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_speed', - 'unit_of_measurement': , - }) -# --- -# name: test_sensor_update_exceptions[CannotConnect][sensor.pyload_speed-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'data_rate', - 'friendly_name': 'pyLoad Speed', - 'unit_of_measurement': , - }), - 'context': , - 'entity_id': 'sensor.pyload_speed', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unavailable', - }) -# --- -# name: test_sensor_update_exceptions[CannotConnect][sensor.pyload_total_downloads-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'state_class': , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_total_downloads', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Total downloads', - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Total downloads', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_total', - 'unit_of_measurement': 'downloads', - }) -# --- -# name: test_sensor_update_exceptions[CannotConnect][sensor.pyload_total_downloads-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'pyLoad Total downloads', - 'state_class': , - 'unit_of_measurement': 'downloads', - }), - 'context': , - 'entity_id': 'sensor.pyload_total_downloads', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unavailable', - }) -# --- -# name: test_sensor_update_exceptions[InvalidAuth][sensor.pyload_active_downloads-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'state_class': , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_active_downloads', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Active downloads', - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Active downloads', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_active', - 'unit_of_measurement': 'downloads', - }) -# --- -# name: test_sensor_update_exceptions[InvalidAuth][sensor.pyload_active_downloads-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'pyLoad Active downloads', - 'state_class': , - 'unit_of_measurement': 'downloads', - }), - 'context': , - 'entity_id': 'sensor.pyload_active_downloads', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '1', - }) -# --- -# name: test_sensor_update_exceptions[InvalidAuth][sensor.pyload_downloads_in_queue-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'state_class': , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_downloads_in_queue', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Downloads in queue', - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Downloads in queue', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_queue', - 'unit_of_measurement': 'downloads', - }) -# --- -# name: test_sensor_update_exceptions[InvalidAuth][sensor.pyload_downloads_in_queue-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'pyLoad Downloads in queue', - 'state_class': , - 'unit_of_measurement': 'downloads', - }), - 'context': , - 'entity_id': 'sensor.pyload_downloads_in_queue', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '6', - }) -# --- -# name: test_sensor_update_exceptions[InvalidAuth][sensor.pyload_free_space-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_free_space', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Free space', - 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 1, - }), - 'sensor.private': dict({ - 'suggested_unit_of_measurement': , - }), - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Free space', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_free_space', - 'unit_of_measurement': , - }) -# --- -# name: test_sensor_update_exceptions[InvalidAuth][sensor.pyload_free_space-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'data_size', - 'friendly_name': 'pyLoad Free space', - 'unit_of_measurement': , - }), - 'context': , - 'entity_id': 'sensor.pyload_free_space', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '93.1322574606165', - }) -# --- -# name: test_sensor_update_exceptions[InvalidAuth][sensor.pyload_speed-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_speed', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Speed', - 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 1, - }), - 'sensor.private': dict({ - 'suggested_unit_of_measurement': , - }), - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Speed', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_speed', - 'unit_of_measurement': , - }) -# --- -# name: test_sensor_update_exceptions[InvalidAuth][sensor.pyload_speed-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'data_rate', - 'friendly_name': 'pyLoad Speed', - 'unit_of_measurement': , - }), - 'context': , - 'entity_id': 'sensor.pyload_speed', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '43.247704', - }) -# --- -# name: test_sensor_update_exceptions[InvalidAuth][sensor.pyload_total_downloads-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'state_class': , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_total_downloads', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Total downloads', - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Total downloads', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_total', - 'unit_of_measurement': 'downloads', - }) -# --- -# name: test_sensor_update_exceptions[InvalidAuth][sensor.pyload_total_downloads-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'pyLoad Total downloads', - 'state_class': , - 'unit_of_measurement': 'downloads', - }), - 'context': , - 'entity_id': 'sensor.pyload_total_downloads', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '37', - }) -# --- -# name: test_sensor_update_exceptions[ParserError][sensor.pyload_active_downloads-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'state_class': , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_active_downloads', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Active downloads', - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Active downloads', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_active', - 'unit_of_measurement': 'downloads', - }) -# --- -# name: test_sensor_update_exceptions[ParserError][sensor.pyload_active_downloads-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'pyLoad Active downloads', - 'state_class': , - 'unit_of_measurement': 'downloads', - }), - 'context': , - 'entity_id': 'sensor.pyload_active_downloads', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unavailable', - }) -# --- -# name: test_sensor_update_exceptions[ParserError][sensor.pyload_downloads_in_queue-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'state_class': , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_downloads_in_queue', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Downloads in queue', - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Downloads in queue', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_queue', - 'unit_of_measurement': 'downloads', - }) -# --- -# name: test_sensor_update_exceptions[ParserError][sensor.pyload_downloads_in_queue-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'pyLoad Downloads in queue', - 'state_class': , - 'unit_of_measurement': 'downloads', - }), - 'context': , - 'entity_id': 'sensor.pyload_downloads_in_queue', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unavailable', - }) -# --- -# name: test_sensor_update_exceptions[ParserError][sensor.pyload_free_space-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_free_space', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Free space', - 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 1, - }), - 'sensor.private': dict({ - 'suggested_unit_of_measurement': , - }), - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Free space', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_free_space', - 'unit_of_measurement': , - }) -# --- -# name: test_sensor_update_exceptions[ParserError][sensor.pyload_free_space-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'data_size', - 'friendly_name': 'pyLoad Free space', - 'unit_of_measurement': , - }), - 'context': , - 'entity_id': 'sensor.pyload_free_space', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unavailable', - }) -# --- -# name: test_sensor_update_exceptions[ParserError][sensor.pyload_speed-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_speed', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Speed', - 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 1, - }), - 'sensor.private': dict({ - 'suggested_unit_of_measurement': , - }), - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Speed', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_speed', - 'unit_of_measurement': , - }) -# --- -# name: test_sensor_update_exceptions[ParserError][sensor.pyload_speed-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'data_rate', - 'friendly_name': 'pyLoad Speed', - 'unit_of_measurement': , - }), - 'context': , - 'entity_id': 'sensor.pyload_speed', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unavailable', - }) -# --- -# name: test_sensor_update_exceptions[ParserError][sensor.pyload_total_downloads-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'state_class': , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.pyload_total_downloads', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Total downloads', - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Total downloads', - 'platform': 'pyload', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'XXXXXXXXXXXXXX_total', - 'unit_of_measurement': 'downloads', - }) -# --- -# name: test_sensor_update_exceptions[ParserError][sensor.pyload_total_downloads-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'pyLoad Total downloads', - 'state_class': , - 'unit_of_measurement': 'downloads', - }), - 'context': , - 'entity_id': 'sensor.pyload_total_downloads', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unavailable', - }) -# --- # name: test_setup[sensor.pyload_active_downloads-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/pyload/test_config_flow.py b/tests/components/pyload/test_config_flow.py index 1eafbd2eb66..08a93858476 100644 --- a/tests/components/pyload/test_config_flow.py +++ b/tests/components/pyload/test_config_flow.py @@ -65,7 +65,7 @@ async def test_form_errors( result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER} ) - mock_pyloadapi.login.side_effect = exception + mock_pyloadapi.get_status.side_effect = exception result = await hass.config_entries.flow.async_configure( result["flow_id"], @@ -75,7 +75,7 @@ async def test_form_errors( assert result["type"] is FlowResultType.FORM assert result["errors"] == {"base": expected_error} - mock_pyloadapi.login.side_effect = None + mock_pyloadapi.get_status.side_effect = None result = await hass.config_entries.flow.async_configure( result["flow_id"], USER_INPUT, @@ -159,7 +159,7 @@ async def test_reauth_errors( assert result["type"] is FlowResultType.FORM assert result["step_id"] == "reauth_confirm" - mock_pyloadapi.login.side_effect = side_effect + mock_pyloadapi.get_status.side_effect = side_effect result = await hass.config_entries.flow.async_configure( result["flow_id"], REAUTH_INPUT, @@ -168,7 +168,7 @@ async def test_reauth_errors( assert result["type"] is FlowResultType.FORM assert result["errors"] == {"base": error_text} - mock_pyloadapi.login.side_effect = None + mock_pyloadapi.get_status.side_effect = None result = await hass.config_entries.flow.async_configure( result["flow_id"], REAUTH_INPUT, @@ -231,7 +231,7 @@ async def test_reconfigure_errors( assert result["type"] is FlowResultType.FORM assert result["step_id"] == "reconfigure" - mock_pyloadapi.login.side_effect = side_effect + mock_pyloadapi.get_status.side_effect = side_effect result = await hass.config_entries.flow.async_configure( result["flow_id"], USER_INPUT, @@ -240,7 +240,7 @@ async def test_reconfigure_errors( assert result["type"] is FlowResultType.FORM assert result["errors"] == {"base": error_text} - mock_pyloadapi.login.side_effect = None + mock_pyloadapi.get_status.side_effect = None result = await hass.config_entries.flow.async_configure( result["flow_id"], USER_INPUT, @@ -261,7 +261,7 @@ async def test_hassio_discovery( ) -> None: """Test flow started from Supervisor discovery.""" - mock_pyloadapi.login.side_effect = InvalidAuth + mock_pyloadapi.get_status.side_effect = InvalidAuth result = await hass.config_entries.flow.async_init( DOMAIN, @@ -273,7 +273,7 @@ async def test_hassio_discovery( assert result["step_id"] == "hassio_confirm" assert result["errors"] is None - mock_pyloadapi.login.side_effect = None + mock_pyloadapi.get_status.side_effect = None result = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_USERNAME: "pyload", CONF_PASSWORD: "pyload"} @@ -325,7 +325,7 @@ async def test_hassio_discovery_errors( ) -> None: """Test flow started from Supervisor discovery.""" - mock_pyloadapi.login.side_effect = side_effect + mock_pyloadapi.get_status.side_effect = side_effect result = await hass.config_entries.flow.async_init( DOMAIN, @@ -344,7 +344,7 @@ async def test_hassio_discovery_errors( assert result["type"] is FlowResultType.FORM assert result["errors"] == {"base": error_text} - mock_pyloadapi.login.side_effect = None + mock_pyloadapi.get_status.side_effect = None result = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_USERNAME: "pyload", CONF_PASSWORD: "pyload"} diff --git a/tests/components/pyload/test_init.py b/tests/components/pyload/test_init.py index 5c85979b9df..c0261051dbd 100644 --- a/tests/components/pyload/test_init.py +++ b/tests/components/pyload/test_init.py @@ -1,9 +1,7 @@ """Test pyLoad init.""" -from datetime import timedelta from unittest.mock import MagicMock -from freezegun.api import FrozenDateTimeFactory from pyloadapi.exceptions import CannotConnect, InvalidAuth, ParserError import pytest @@ -11,7 +9,7 @@ from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState from homeassistant.const import CONF_PATH, CONF_URL from homeassistant.core import HomeAssistant -from tests.common import MockConfigEntry, async_fire_time_changed +from tests.common import MockConfigEntry async def test_entry_setup_unload( @@ -44,7 +42,7 @@ async def test_config_entry_setup_errors( side_effect: Exception, ) -> None: """Test config entry not ready.""" - mock_pyloadapi.login.side_effect = side_effect + mock_pyloadapi.version.side_effect = side_effect config_entry.add_to_hass(hass) await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() @@ -58,7 +56,7 @@ async def test_config_entry_setup_invalid_auth( mock_pyloadapi: MagicMock, ) -> None: """Test config entry authentication.""" - mock_pyloadapi.login.side_effect = InvalidAuth + mock_pyloadapi.version.side_effect = InvalidAuth config_entry.add_to_hass(hass) await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() @@ -72,25 +70,61 @@ async def test_coordinator_update_invalid_auth( hass: HomeAssistant, config_entry: MockConfigEntry, mock_pyloadapi: MagicMock, - freezer: FrozenDateTimeFactory, ) -> None: """Test coordinator authentication.""" + mock_pyloadapi.get_status.side_effect = InvalidAuth + config_entry.add_to_hass(hass) await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() - assert config_entry.state is ConfigEntryState.LOADED - - mock_pyloadapi.login.side_effect = InvalidAuth - mock_pyloadapi.get_status.side_effect = InvalidAuth - - freezer.tick(timedelta(seconds=20)) - async_fire_time_changed(hass) - await hass.async_block_till_done() + assert config_entry.state is ConfigEntryState.SETUP_ERROR assert any(config_entry.async_get_active_flows(hass, {SOURCE_REAUTH})) +async def test_coordinator_setup_invalid_auth( + hass: HomeAssistant, + config_entry: MockConfigEntry, + mock_pyloadapi: MagicMock, +) -> None: + """Test coordinator setup authentication.""" + mock_pyloadapi.version.side_effect = InvalidAuth + + config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + assert config_entry.state is ConfigEntryState.SETUP_ERROR + + assert any(config_entry.async_get_active_flows(hass, {SOURCE_REAUTH})) + + +@pytest.mark.parametrize( + ("exception", "state"), + [ + (CannotConnect, ConfigEntryState.SETUP_RETRY), + (InvalidAuth, ConfigEntryState.SETUP_ERROR), + (ParserError, ConfigEntryState.SETUP_RETRY), + ], +) +async def test_coordinator_update_errors( + hass: HomeAssistant, + config_entry: MockConfigEntry, + mock_pyloadapi: MagicMock, + exception: Exception, + state: ConfigEntryState, +) -> None: + """Test coordinator setup authentication.""" + mock_pyloadapi.get_status.side_effect = exception + + config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + assert config_entry.state is state + + @pytest.mark.usefixtures("mock_pyloadapi") async def test_migration( hass: HomeAssistant, diff --git a/tests/components/pyload/test_sensor.py b/tests/components/pyload/test_sensor.py index 33ad3435083..415446889c3 100644 --- a/tests/components/pyload/test_sensor.py +++ b/tests/components/pyload/test_sensor.py @@ -3,18 +3,15 @@ from collections.abc import Generator from unittest.mock import AsyncMock, patch -from freezegun.api import FrozenDateTimeFactory -from pyloadapi.exceptions import CannotConnect, InvalidAuth, ParserError import pytest from syrupy.assertion import SnapshotAssertion -from homeassistant.components.pyload.coordinator import SCAN_INTERVAL from homeassistant.config_entries import ConfigEntryState from homeassistant.const import Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er -from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform +from tests.common import MockConfigEntry, snapshot_platform @pytest.fixture(autouse=True) @@ -42,78 +39,3 @@ async def test_setup( assert config_entry.state is ConfigEntryState.LOADED await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id) - - -@pytest.mark.parametrize( - "exception", - [CannotConnect, InvalidAuth, ParserError], -) -async def test_sensor_update_exceptions( - hass: HomeAssistant, - config_entry: MockConfigEntry, - mock_pyloadapi: AsyncMock, - exception: Exception, - snapshot: SnapshotAssertion, - entity_registry: er.EntityRegistry, - freezer: FrozenDateTimeFactory, -) -> None: - """Test if pyLoad sensors go unavailable when exceptions occur (except ParserErrors).""" - - config_entry.add_to_hass(hass) - await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - - mock_pyloadapi.get_status.side_effect = exception - freezer.tick(SCAN_INTERVAL) - async_fire_time_changed(hass) - await hass.async_block_till_done() - - await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id) - - -async def test_sensor_invalid_auth( - hass: HomeAssistant, - config_entry: MockConfigEntry, - mock_pyloadapi: AsyncMock, - caplog: pytest.LogCaptureFixture, - freezer: FrozenDateTimeFactory, -) -> None: - """Test invalid auth during sensor update.""" - - config_entry.add_to_hass(hass) - await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - - mock_pyloadapi.get_status.side_effect = InvalidAuth - mock_pyloadapi.login.side_effect = InvalidAuth - - freezer.tick(SCAN_INTERVAL) - async_fire_time_changed(hass) - await hass.async_block_till_done() - - assert ( - "Authentication failed for username, verify your login credentials" - in caplog.text - ) - - -async def test_pyload_pre_0_5_0( - hass: HomeAssistant, - config_entry: MockConfigEntry, - mock_pyloadapi: AsyncMock, -) -> None: - """Test setup of the pyload sensor platform.""" - mock_pyloadapi.get_status.return_value = { - "pause": False, - "active": 1, - "queue": 6, - "total": 37, - "speed": 5405963.0, - "download": True, - "reconnect": False, - } - config_entry.add_to_hass(hass) - await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - - assert config_entry.state is ConfigEntryState.LOADED