Fix RootFolder not iterable in Radarr (#97537)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
This commit is contained in:
parent
085e274f44
commit
c2e9fd85c2
6 changed files with 189 additions and 28 deletions
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from datetime import timedelta
|
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 import Health, RadarrMovie, RootFolder, SystemStatus, exceptions
|
||||||
from aiopyarr.models.host_configuration import PyArrHostConfiguration
|
from aiopyarr.models.host_configuration import PyArrHostConfiguration
|
||||||
|
@ -71,7 +71,10 @@ class DiskSpaceDataUpdateCoordinator(RadarrDataUpdateCoordinator[list[RootFolder
|
||||||
|
|
||||||
async def _fetch_data(self) -> list[RootFolder]:
|
async def _fetch_data(self) -> list[RootFolder]:
|
||||||
"""Fetch the data."""
|
"""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]]):
|
class HealthDataUpdateCoordinator(RadarrDataUpdateCoordinator[list[Health]]):
|
||||||
|
@ -87,4 +90,7 @@ class MoviesDataUpdateCoordinator(RadarrDataUpdateCoordinator[int]):
|
||||||
|
|
||||||
async def _fetch_data(self) -> int:
|
async def _fetch_data(self) -> int:
|
||||||
"""Fetch the movies data."""
|
"""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)
|
||||||
|
|
|
@ -41,6 +41,7 @@ def mock_connection(
|
||||||
error: bool = False,
|
error: bool = False,
|
||||||
invalid_auth: bool = False,
|
invalid_auth: bool = False,
|
||||||
windows: bool = False,
|
windows: bool = False,
|
||||||
|
single_return: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Mock radarr connection."""
|
"""Mock radarr connection."""
|
||||||
if error:
|
if error:
|
||||||
|
@ -75,22 +76,27 @@ def mock_connection(
|
||||||
headers={"Content-Type": CONTENT_TYPE_JSON},
|
headers={"Content-Type": CONTENT_TYPE_JSON},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
root_folder_fixture = "rootfolder-linux"
|
||||||
|
|
||||||
if windows:
|
if windows:
|
||||||
|
root_folder_fixture = "rootfolder-windows"
|
||||||
|
|
||||||
|
if single_return:
|
||||||
|
root_folder_fixture = f"single-{root_folder_fixture}"
|
||||||
|
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
f"{url}/api/v3/rootfolder",
|
f"{url}/api/v3/rootfolder",
|
||||||
text=load_fixture("radarr/rootfolder-windows.json"),
|
text=load_fixture(f"radarr/{root_folder_fixture}.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},
|
headers={"Content-Type": CONTENT_TYPE_JSON},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
movie_fixture = "movie"
|
||||||
|
if single_return:
|
||||||
|
movie_fixture = f"single-{movie_fixture}"
|
||||||
|
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
f"{url}/api/v3/movie",
|
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},
|
headers={"Content-Type": CONTENT_TYPE_JSON},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -139,6 +145,7 @@ async def setup_integration(
|
||||||
connection_error: bool = False,
|
connection_error: bool = False,
|
||||||
invalid_auth: bool = False,
|
invalid_auth: bool = False,
|
||||||
windows: bool = False,
|
windows: bool = False,
|
||||||
|
single_return: bool = False,
|
||||||
) -> MockConfigEntry:
|
) -> MockConfigEntry:
|
||||||
"""Set up the radarr integration in Home Assistant."""
|
"""Set up the radarr integration in Home Assistant."""
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
|
@ -159,6 +166,7 @@ async def setup_integration(
|
||||||
error=connection_error,
|
error=connection_error,
|
||||||
invalid_auth=invalid_auth,
|
invalid_auth=invalid_auth,
|
||||||
windows=windows,
|
windows=windows,
|
||||||
|
single_return=single_return,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not skip_entry_setup:
|
if not skip_entry_setup:
|
||||||
|
@ -183,7 +191,7 @@ def patch_radarr():
|
||||||
|
|
||||||
|
|
||||||
def create_entry(hass: HomeAssistant) -> MockConfigEntry:
|
def create_entry(hass: HomeAssistant) -> MockConfigEntry:
|
||||||
"""Create Efergy entry in Home Assistant."""
|
"""Create Radarr entry in Home Assistant."""
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
data={
|
data={
|
||||||
|
|
116
tests/components/radarr/fixtures/single-movie.json
Normal file
116
tests/components/radarr/fixtures/single-movie.json
Normal file
|
@ -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"
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"path": "/downloads",
|
||||||
|
"freeSpace": 282500064232,
|
||||||
|
"unmappedFolders": [],
|
||||||
|
"id": 1
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"path": "D:\\Downloads\\TV",
|
||||||
|
"freeSpace": 282500064232,
|
||||||
|
"unmappedFolders": [],
|
||||||
|
"id": 1
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
"""The tests for Radarr sensor platform."""
|
"""The tests for Radarr sensor platform."""
|
||||||
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.sensor import SensorDeviceClass
|
from homeassistant.components.sensor import SensorDeviceClass
|
||||||
from homeassistant.const import ATTR_DEVICE_CLASS, ATTR_UNIT_OF_MEASUREMENT
|
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
|
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(
|
async def test_sensors(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
aioclient_mock: AiohttpClientMocker,
|
aioclient_mock: AiohttpClientMocker,
|
||||||
entity_registry_enabled_by_default: None,
|
entity_registry_enabled_by_default: None,
|
||||||
|
windows: bool,
|
||||||
|
single: bool,
|
||||||
|
root_folder: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test for successfully setting up the Radarr platform."""
|
"""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.state == "263.10"
|
||||||
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "GB"
|
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "GB"
|
||||||
state = hass.states.get("sensor.mock_title_movies")
|
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")
|
state = hass.states.get("sensor.mock_title_start_time")
|
||||||
assert state.state == "2020-09-01T23:50:20+00:00"
|
assert state.state == "2020-09-01T23:50:20+00:00"
|
||||||
assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.TIMESTAMP
|
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"
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue