From c2e9fd85c20a28619c43499b689f58245a158d41 Mon Sep 17 00:00:00 2001 From: Joost Lekkerkerker Date: Mon, 31 Jul 2023 18:44:03 +0200 Subject: [PATCH] Fix RootFolder not iterable in Radarr (#97537) Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> --- .../components/radarr/coordinator.py | 12 +- tests/components/radarr/__init__.py | 34 +++-- .../radarr/fixtures/single-movie.json | 116 ++++++++++++++++++ .../fixtures/single-rootfolder-linux.json | 6 + .../fixtures/single-rootfolder-windows.json | 6 + tests/components/radarr/test_sensor.py | 43 +++++-- 6 files changed, 189 insertions(+), 28 deletions(-) create mode 100644 tests/components/radarr/fixtures/single-movie.json create mode 100644 tests/components/radarr/fixtures/single-rootfolder-linux.json create mode 100644 tests/components/radarr/fixtures/single-rootfolder-windows.json diff --git a/homeassistant/components/radarr/coordinator.py b/homeassistant/components/radarr/coordinator.py index 5537a18725c..c318d662028 100644 --- a/homeassistant/components/radarr/coordinator.py +++ b/homeassistant/components/radarr/coordinator.py @@ -3,7 +3,7 @@ from __future__ import annotations from abc import ABC, abstractmethod from datetime import timedelta -from typing import Generic, TypeVar, cast +from typing import Generic, TypeVar from aiopyarr import Health, RadarrMovie, RootFolder, SystemStatus, exceptions from aiopyarr.models.host_configuration import PyArrHostConfiguration @@ -71,7 +71,10 @@ class DiskSpaceDataUpdateCoordinator(RadarrDataUpdateCoordinator[list[RootFolder async def _fetch_data(self) -> list[RootFolder]: """Fetch the data.""" - return cast(list[RootFolder], await self.api_client.async_get_root_folders()) + root_folders = await self.api_client.async_get_root_folders() + if isinstance(root_folders, RootFolder): + root_folders = [root_folders] + return root_folders class HealthDataUpdateCoordinator(RadarrDataUpdateCoordinator[list[Health]]): @@ -87,4 +90,7 @@ class MoviesDataUpdateCoordinator(RadarrDataUpdateCoordinator[int]): async def _fetch_data(self) -> int: """Fetch the movies data.""" - return len(cast(list[RadarrMovie], await self.api_client.async_get_movies())) + movies = await self.api_client.async_get_movies() + if isinstance(movies, RadarrMovie): + return 1 + return len(movies) diff --git a/tests/components/radarr/__init__.py b/tests/components/radarr/__init__.py index 7e574b1e3e0..069eeabe8d8 100644 --- a/tests/components/radarr/__init__.py +++ b/tests/components/radarr/__init__.py @@ -41,6 +41,7 @@ def mock_connection( error: bool = False, invalid_auth: bool = False, windows: bool = False, + single_return: bool = False, ) -> None: """Mock radarr connection.""" if error: @@ -75,22 +76,27 @@ def mock_connection( headers={"Content-Type": CONTENT_TYPE_JSON}, ) + root_folder_fixture = "rootfolder-linux" + if windows: - aioclient_mock.get( - f"{url}/api/v3/rootfolder", - text=load_fixture("radarr/rootfolder-windows.json"), - headers={"Content-Type": CONTENT_TYPE_JSON}, - ) - else: - aioclient_mock.get( - f"{url}/api/v3/rootfolder", - text=load_fixture("radarr/rootfolder-linux.json"), - headers={"Content-Type": CONTENT_TYPE_JSON}, - ) + root_folder_fixture = "rootfolder-windows" + + if single_return: + root_folder_fixture = f"single-{root_folder_fixture}" + + aioclient_mock.get( + f"{url}/api/v3/rootfolder", + text=load_fixture(f"radarr/{root_folder_fixture}.json"), + headers={"Content-Type": CONTENT_TYPE_JSON}, + ) + + movie_fixture = "movie" + if single_return: + movie_fixture = f"single-{movie_fixture}" aioclient_mock.get( f"{url}/api/v3/movie", - text=load_fixture("radarr/movie.json"), + text=load_fixture(f"radarr/{movie_fixture}.json"), headers={"Content-Type": CONTENT_TYPE_JSON}, ) @@ -139,6 +145,7 @@ async def setup_integration( connection_error: bool = False, invalid_auth: bool = False, windows: bool = False, + single_return: bool = False, ) -> MockConfigEntry: """Set up the radarr integration in Home Assistant.""" entry = MockConfigEntry( @@ -159,6 +166,7 @@ async def setup_integration( error=connection_error, invalid_auth=invalid_auth, windows=windows, + single_return=single_return, ) if not skip_entry_setup: @@ -183,7 +191,7 @@ def patch_radarr(): def create_entry(hass: HomeAssistant) -> MockConfigEntry: - """Create Efergy entry in Home Assistant.""" + """Create Radarr entry in Home Assistant.""" entry = MockConfigEntry( domain=DOMAIN, data={ diff --git a/tests/components/radarr/fixtures/single-movie.json b/tests/components/radarr/fixtures/single-movie.json new file mode 100644 index 00000000000..db9e720d285 --- /dev/null +++ b/tests/components/radarr/fixtures/single-movie.json @@ -0,0 +1,116 @@ +{ + "id": 0, + "title": "string", + "originalTitle": "string", + "alternateTitles": [ + { + "sourceType": "tmdb", + "movieId": 1, + "title": "string", + "sourceId": 0, + "votes": 0, + "voteCount": 0, + "language": { + "id": 1, + "name": "English" + }, + "id": 1 + } + ], + "sortTitle": "string", + "sizeOnDisk": 0, + "overview": "string", + "inCinemas": "2020-11-06T00:00:00Z", + "physicalRelease": "2019-03-19T00:00:00Z", + "images": [ + { + "coverType": "poster", + "url": "string", + "remoteUrl": "string" + } + ], + "website": "string", + "year": 0, + "hasFile": true, + "youTubeTrailerId": "string", + "studio": "string", + "path": "string", + "rootFolderPath": "string", + "qualityProfileId": 0, + "monitored": true, + "minimumAvailability": "announced", + "isAvailable": true, + "folderName": "string", + "runtime": 0, + "cleanTitle": "string", + "imdbId": "string", + "tmdbId": 0, + "titleSlug": "string", + "certification": "string", + "genres": ["string"], + "tags": [0], + "added": "2018-12-28T05:56:49Z", + "ratings": { + "votes": 0, + "value": 0 + }, + "movieFile": { + "movieId": 0, + "relativePath": "string", + "path": "string", + "size": 916662234, + "dateAdded": "2020-11-26T02:00:35Z", + "indexerFlags": 1, + "quality": { + "quality": { + "id": 14, + "name": "WEBRip-720p", + "source": "webrip", + "resolution": 720, + "modifier": "none" + }, + "revision": { + "version": 1, + "real": 0, + "isRepack": false + } + }, + "mediaInfo": { + "audioBitrate": 0, + "audioChannels": 2, + "audioCodec": "AAC", + "audioLanguages": "", + "audioStreamCount": 1, + "videoBitDepth": 8, + "videoBitrate": 1000000, + "videoCodec": "x264", + "videoFps": 25.0, + "resolution": "1280x534", + "runTime": "1:49:06", + "scanType": "Progressive", + "subtitles": "" + }, + "originalFilePath": "string", + "qualityCutoffNotMet": true, + "languages": [ + { + "id": 26, + "name": "Hindi" + } + ], + "edition": "", + "id": 35361 + }, + "collection": { + "name": "string", + "tmdbId": 0, + "images": [ + { + "coverType": "poster", + "url": "string", + "remoteUrl": "string" + } + ] + }, + "status": "deleted" +} diff --git a/tests/components/radarr/fixtures/single-rootfolder-linux.json b/tests/components/radarr/fixtures/single-rootfolder-linux.json new file mode 100644 index 00000000000..085467fda6a --- /dev/null +++ b/tests/components/radarr/fixtures/single-rootfolder-linux.json @@ -0,0 +1,6 @@ +{ + "path": "/downloads", + "freeSpace": 282500064232, + "unmappedFolders": [], + "id": 1 +} diff --git a/tests/components/radarr/fixtures/single-rootfolder-windows.json b/tests/components/radarr/fixtures/single-rootfolder-windows.json new file mode 100644 index 00000000000..25a93baa10d --- /dev/null +++ b/tests/components/radarr/fixtures/single-rootfolder-windows.json @@ -0,0 +1,6 @@ +{ + "path": "D:\\Downloads\\TV", + "freeSpace": 282500064232, + "unmappedFolders": [], + "id": 1 +} diff --git a/tests/components/radarr/test_sensor.py b/tests/components/radarr/test_sensor.py index d3dde74dcbf..f4f863d9bb6 100644 --- a/tests/components/radarr/test_sensor.py +++ b/tests/components/radarr/test_sensor.py @@ -1,4 +1,5 @@ """The tests for Radarr sensor platform.""" +import pytest from homeassistant.components.sensor import SensorDeviceClass from homeassistant.const import ATTR_DEVICE_CLASS, ATTR_UNIT_OF_MEASUREMENT @@ -9,15 +10,43 @@ from . import setup_integration from tests.test_util.aiohttp import AiohttpClientMocker +@pytest.mark.parametrize( + ("windows", "single", "root_folder"), + [ + ( + False, + False, + "downloads", + ), + ( + False, + True, + "downloads", + ), + ( + True, + False, + "tv", + ), + ( + True, + True, + "tv", + ), + ], +) async def test_sensors( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, entity_registry_enabled_by_default: None, + windows: bool, + single: bool, + root_folder: str, ) -> None: """Test for successfully setting up the Radarr platform.""" - await setup_integration(hass, aioclient_mock) + await setup_integration(hass, aioclient_mock, windows=windows, single_return=single) - state = hass.states.get("sensor.mock_title_disk_space_downloads") + state = hass.states.get(f"sensor.mock_title_disk_space_{root_folder}") assert state.state == "263.10" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "GB" state = hass.states.get("sensor.mock_title_movies") @@ -26,13 +55,3 @@ async def test_sensors( state = hass.states.get("sensor.mock_title_start_time") assert state.state == "2020-09-01T23:50:20+00:00" assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.TIMESTAMP - - -async def test_windows( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker -) -> None: - """Test for successfully setting up the Radarr platform on Windows.""" - await setup_integration(hass, aioclient_mock, windows=True) - - state = hass.states.get("sensor.mock_title_disk_space_tv") - assert state.state == "263.10"