1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-19 18:38:58 +00:00

Add support for errored torrents in qBittorrent sensor (#153120)

Co-authored-by: Joostlek <joostlek@outlook.com>
This commit is contained in:
Aviad Levy
2025-10-01 00:34:15 +03:00
committed by GitHub
parent 7d1a0be07e
commit 1b495ecafa
7 changed files with 1241 additions and 0 deletions

View File

@@ -39,6 +39,7 @@ SENSOR_TYPE_ALL_TORRENTS = "all_torrents"
SENSOR_TYPE_PAUSED_TORRENTS = "paused_torrents"
SENSOR_TYPE_ACTIVE_TORRENTS = "active_torrents"
SENSOR_TYPE_INACTIVE_TORRENTS = "inactive_torrents"
SENSOR_TYPE_ERRORED_TORRENTS = "errored_torrents"
def get_state(coordinator: QBittorrentDataCoordinator) -> str:
@@ -221,6 +222,13 @@ SENSOR_TYPES: tuple[QBittorrentSensorEntityDescription, ...] = (
coordinator, ["stoppedDL", "stoppedUP"]
),
),
QBittorrentSensorEntityDescription(
key=SENSOR_TYPE_ERRORED_TORRENTS,
translation_key="errored_torrents",
value_fn=lambda coordinator: count_torrents_in_states(
coordinator, ["error", "missingFiles"]
),
),
)

View File

@@ -18,6 +18,7 @@ get_torrents:
- "all"
- "seeding"
- "started"
- "errored"
get_all_torrents:
fields:
torrent_filter:
@@ -33,3 +34,4 @@ get_all_torrents:
- "all"
- "seeding"
- "started"
- "errored"

View File

@@ -70,6 +70,10 @@
"name": "Paused torrents",
"unit_of_measurement": "[%key:component::qbittorrent::entity::sensor::active_torrents::unit_of_measurement%]"
},
"errored_torrents": {
"name": "Errored torrents",
"unit_of_measurement": "[%key:component::qbittorrent::entity::sensor::active_torrents::unit_of_measurement%]"
},
"all_torrents": {
"name": "All torrents",
"unit_of_measurement": "[%key:component::qbittorrent::entity::sensor::active_torrents::unit_of_measurement%]"

View File

@@ -6,6 +6,11 @@ from unittest.mock import AsyncMock, patch
import pytest
import requests_mock
from homeassistant.components.qbittorrent import DOMAIN
from homeassistant.const import CONF_PASSWORD, CONF_URL, CONF_USERNAME, CONF_VERIFY_SSL
from tests.common import MockConfigEntry, load_json_object_fixture
@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock]:
@@ -24,3 +29,31 @@ def mock_api() -> Generator[requests_mock.Mocker]:
mocker.get("http://localhost:8080/api/v2/transfer/speedLimitsMode")
mocker.post("http://localhost:8080/api/v2/auth/login", text="Ok.")
yield mocker
@pytest.fixture
def mock_qbittorrent() -> Generator[AsyncMock]:
"""Mock qbittorrent client."""
with patch(
"homeassistant.components.qbittorrent.helpers.Client", autospec=True
) as mock_client:
client = mock_client.return_value
client.sync_maindata.return_value = load_json_object_fixture(
"sync_maindata.json", DOMAIN
)
yield client
@pytest.fixture
def mock_config_entry() -> MockConfigEntry:
"""Create a mock config entry for qbittorrent."""
return MockConfigEntry(
domain=DOMAIN,
data={
CONF_URL: "http://localhost:8080",
CONF_USERNAME: "admin",
CONF_PASSWORD: "adminadmin",
CONF_VERIFY_SSL: False,
},
entry_id="01K6E7464PTQKDE24VAJQZPTH2",
)

View File

@@ -0,0 +1,392 @@
{
"categories": {
"radarr": {
"name": "radarr",
"savePath": ""
}
},
"full_update": true,
"rid": 2,
"server_state": {
"alltime_dl": 861098349149,
"alltime_ul": 724759510499,
"average_time_queue": 27,
"connection_status": "connected",
"dht_nodes": 370,
"dl_info_data": 127006787927,
"dl_info_speed": 0,
"dl_rate_limit": 0,
"free_space_on_disk": 87547486208,
"global_ratio": "0.84",
"last_external_address_v4": "1.1.1.1",
"last_external_address_v6": "",
"queued_io_jobs": 0,
"queueing": true,
"read_cache_hits": "0",
"read_cache_overload": "0",
"refresh_interval": 1500,
"total_buffers_size": 0,
"total_peer_connections": 2,
"total_queued_size": 0,
"total_wasted_session": 374937191,
"up_info_data": 119803126285,
"up_info_speed": 0,
"up_rate_limit": 0,
"use_alt_speed_limits": false,
"use_subcategories": false,
"write_cache_overload": "0"
},
"torrents": {
"cb48f83c1f1f7bb781e9c4af1602a14df7a915fe": {
"added_on": 1751736848,
"amount_left": 89178112,
"auto_tmm": false,
"availability": 0.6449999809265137,
"category": "radarr",
"comment": "",
"completed": 167913804,
"completion_on": -1,
"content_path": "/download_mnt/incomplete/ubuntu",
"dl_limit": 0,
"dlspeed": 0,
"download_path": "/download_mnt/incomplete",
"downloaded": 167941419,
"downloaded_session": 0,
"eta": 8640000,
"f_l_piece_prio": false,
"force_start": false,
"has_metadata": true,
"inactive_seeding_time_limit": -2,
"infohash_v1": "asdasdasdasd",
"infohash_v2": "",
"last_activity": 1751896934,
"magnet_uri": "magnet:?xt=urn:btih:ubuntu",
"max_inactive_seeding_time": -1,
"max_ratio": 1,
"max_seeding_time": 120,
"name": "ubuntu",
"num_complete": 0,
"num_incomplete": 2,
"num_leechs": 0,
"num_seeds": 0,
"popularity": 0,
"priority": 1,
"private": false,
"progress": 0.6531275141300048,
"ratio": 0,
"ratio_limit": -2,
"reannounce": 79,
"root_path": "/download_mnt/incomplete/ubuntu",
"save_path": "/download_mnt/complete",
"seeding_time": 0,
"seeding_time_limit": -2,
"seen_complete": 1756425055,
"seq_dl": false,
"size": 257091916,
"state": "stalledDL",
"super_seeding": false,
"tags": "",
"time_active": 7528849,
"total_size": 257091916,
"tracker": "http://tracker.ubuntu.com:2710/announce",
"trackers_count": 34,
"up_limit": 0,
"uploaded": 0,
"uploaded_session": 0,
"upspeed": 0
},
"cb48f83c1f1f7bb781e9c4af1602a14df7a915fb": {
"added_on": 1751736848,
"amount_left": 89178112,
"auto_tmm": false,
"availability": 0.6449999809265137,
"category": "radarr",
"comment": "",
"completed": 167913804,
"completion_on": -1,
"content_path": "/download_mnt/incomplete/ubuntu",
"dl_limit": 0,
"dlspeed": 0,
"download_path": "/download_mnt/incomplete",
"downloaded": 167941419,
"downloaded_session": 0,
"eta": 8640000,
"f_l_piece_prio": false,
"force_start": false,
"has_metadata": true,
"inactive_seeding_time_limit": -2,
"infohash_v1": "asdasdasdasd",
"infohash_v2": "",
"last_activity": 1751896934,
"magnet_uri": "magnet:?xt=urn:btih:ubuntu",
"max_inactive_seeding_time": -1,
"max_ratio": 1,
"max_seeding_time": 120,
"name": "ubuntu",
"num_complete": 0,
"num_incomplete": 2,
"num_leechs": 0,
"num_seeds": 0,
"popularity": 0,
"priority": 1,
"private": false,
"progress": 0.6531275141300048,
"ratio": 0,
"ratio_limit": -2,
"reannounce": 79,
"root_path": "/download_mnt/incomplete/ubuntu",
"save_path": "/download_mnt/complete",
"seeding_time": 0,
"seeding_time_limit": -2,
"seen_complete": 1756425055,
"seq_dl": false,
"size": 257091916,
"state": "stoppedDL",
"super_seeding": false,
"tags": "",
"time_active": 7528849,
"total_size": 257091916,
"tracker": "http://tracker.ubuntu.com:2710/announce",
"trackers_count": 34,
"up_limit": 0,
"uploaded": 0,
"uploaded_session": 0,
"upspeed": 0
},
"cb48f83c1f1f7bb781e9c4af1602a14df7a915fc": {
"added_on": 1751736848,
"amount_left": 89178112,
"auto_tmm": false,
"availability": 0.6449999809265137,
"category": "radarr",
"comment": "",
"completed": 167913804,
"completion_on": -1,
"content_path": "/download_mnt/incomplete/ubuntu",
"dl_limit": 0,
"dlspeed": 0,
"download_path": "/download_mnt/incomplete",
"downloaded": 167941419,
"downloaded_session": 0,
"eta": 8640000,
"f_l_piece_prio": false,
"force_start": false,
"has_metadata": true,
"inactive_seeding_time_limit": -2,
"infohash_v1": "asdasdasdasd",
"infohash_v2": "",
"last_activity": 1751896934,
"magnet_uri": "magnet:?xt=urn:btih:ubuntu",
"max_inactive_seeding_time": -1,
"max_ratio": 1,
"max_seeding_time": 120,
"name": "ubuntu",
"num_complete": 0,
"num_incomplete": 2,
"num_leechs": 0,
"num_seeds": 0,
"popularity": 0,
"priority": 1,
"private": false,
"progress": 0.6531275141300048,
"ratio": 0,
"ratio_limit": -2,
"reannounce": 79,
"root_path": "/download_mnt/incomplete/ubuntu",
"save_path": "/download_mnt/complete",
"seeding_time": 0,
"seeding_time_limit": -2,
"seen_complete": 1756425055,
"seq_dl": false,
"size": 257091916,
"state": "stalledUP",
"super_seeding": false,
"tags": "",
"time_active": 7528849,
"total_size": 257091916,
"tracker": "http://tracker.ubuntu.com:2710/announce",
"trackers_count": 34,
"up_limit": 0,
"uploaded": 0,
"uploaded_session": 0,
"upspeed": 0
},
"cb48f83c1f1f7bb781e9c4af1602a14df7a915fd": {
"added_on": 1751736848,
"amount_left": 89178112,
"auto_tmm": false,
"availability": 0.6449999809265137,
"category": "radarr",
"comment": "",
"completed": 167913804,
"completion_on": -1,
"content_path": "/download_mnt/incomplete/ubuntu",
"dl_limit": 0,
"dlspeed": 0,
"download_path": "/download_mnt/incomplete",
"downloaded": 167941419,
"downloaded_session": 0,
"eta": 8640000,
"f_l_piece_prio": false,
"force_start": false,
"has_metadata": true,
"inactive_seeding_time_limit": -2,
"infohash_v1": "asdasdasdasd",
"infohash_v2": "",
"last_activity": 1751896934,
"magnet_uri": "magnet:?xt=urn:btih:ubuntu",
"max_inactive_seeding_time": -1,
"max_ratio": 1,
"max_seeding_time": 120,
"name": "ubuntu",
"num_complete": 0,
"num_incomplete": 2,
"num_leechs": 0,
"num_seeds": 0,
"popularity": 0,
"priority": 1,
"private": false,
"progress": 0.6531275141300048,
"ratio": 0,
"ratio_limit": -2,
"reannounce": 79,
"root_path": "/download_mnt/incomplete/ubuntu",
"save_path": "/download_mnt/complete",
"seeding_time": 0,
"seeding_time_limit": -2,
"seen_complete": 1756425055,
"seq_dl": false,
"size": 257091916,
"state": "error",
"super_seeding": false,
"tags": "",
"time_active": 7528849,
"total_size": 257091916,
"tracker": "http://tracker.ubuntu.com:2710/announce",
"trackers_count": 34,
"up_limit": 0,
"uploaded": 0,
"uploaded_session": 0,
"upspeed": 0
},
"cb48f83c1f1f7bb781e9c4af1602a14df7a915ff": {
"added_on": 1751736848,
"amount_left": 89178112,
"auto_tmm": false,
"availability": 0.6449999809265137,
"category": "radarr",
"comment": "",
"completed": 167913804,
"completion_on": -1,
"content_path": "/download_mnt/incomplete/ubuntu",
"dl_limit": 0,
"dlspeed": 0,
"download_path": "/download_mnt/incomplete",
"downloaded": 167941419,
"downloaded_session": 0,
"eta": 8640000,
"f_l_piece_prio": false,
"force_start": false,
"has_metadata": true,
"inactive_seeding_time_limit": -2,
"infohash_v1": "asdasdasdasd",
"infohash_v2": "",
"last_activity": 1751896934,
"magnet_uri": "magnet:?xt=urn:btih:ubuntu",
"max_inactive_seeding_time": -1,
"max_ratio": 1,
"max_seeding_time": 120,
"name": "ubuntu",
"num_complete": 0,
"num_incomplete": 2,
"num_leechs": 0,
"num_seeds": 0,
"popularity": 0,
"priority": 1,
"private": false,
"progress": 0.6531275141300048,
"ratio": 0,
"ratio_limit": -2,
"reannounce": 79,
"root_path": "/download_mnt/incomplete/ubuntu",
"save_path": "/download_mnt/complete",
"seeding_time": 0,
"seeding_time_limit": -2,
"seen_complete": 1756425055,
"seq_dl": false,
"size": 257091916,
"state": "missingFiles",
"super_seeding": false,
"tags": "",
"time_active": 7528849,
"total_size": 257091916,
"tracker": "http://tracker.ubuntu.com:2710/announce",
"trackers_count": 34,
"up_limit": 0,
"uploaded": 0,
"uploaded_session": 0,
"upspeed": 0
},
"cb48f83c1f1f7bb781e9c4af1602a14df7a915fa": {
"added_on": 1751736848,
"amount_left": 89178112,
"auto_tmm": false,
"availability": 0.6449999809265137,
"category": "radarr",
"comment": "",
"completed": 167913804,
"completion_on": -1,
"content_path": "/download_mnt/incomplete/ubuntu",
"dl_limit": 0,
"dlspeed": 0,
"download_path": "/download_mnt/incomplete",
"downloaded": 167941419,
"downloaded_session": 0,
"eta": 8640000,
"f_l_piece_prio": false,
"force_start": false,
"has_metadata": true,
"inactive_seeding_time_limit": -2,
"infohash_v1": "asdasdasdasd",
"infohash_v2": "",
"last_activity": 1751896934,
"magnet_uri": "magnet:?xt=urn:btih:ubuntu",
"max_inactive_seeding_time": -1,
"max_ratio": 1,
"max_seeding_time": 120,
"name": "ubuntu",
"num_complete": 0,
"num_incomplete": 2,
"num_leechs": 0,
"num_seeds": 0,
"popularity": 0,
"priority": 1,
"private": false,
"progress": 0.6531275141300048,
"ratio": 0,
"ratio_limit": -2,
"reannounce": 79,
"root_path": "/download_mnt/incomplete/ubuntu",
"save_path": "/download_mnt/complete",
"seeding_time": 0,
"seeding_time_limit": -2,
"seen_complete": 1756425055,
"seq_dl": false,
"size": 257091916,
"state": "downloading",
"super_seeding": false,
"tags": "",
"time_active": 7528849,
"total_size": 257091916,
"tracker": "http://tracker.ubuntu.com:2710/announce",
"trackers_count": 34,
"up_limit": 0,
"uploaded": 0,
"uploaded_session": 0,
"upspeed": 0
}
},
"trackers": {
"http://tracker.ipv6tracker.org:80/announce": ["abc"]
}
}

View File

@@ -0,0 +1,773 @@
# serializer version: 1
# name: test_entities[sensor.mock_title_active_torrents-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_active_torrents',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Active torrents',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'active_torrents',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-active_torrents',
'unit_of_measurement': 'torrents',
})
# ---
# name: test_entities[sensor.mock_title_active_torrents-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Active torrents',
'unit_of_measurement': 'torrents',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_active_torrents',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1',
})
# ---
# name: test_entities[sensor.mock_title_all_time_download-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_all_time_download',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
'sensor.private': dict({
'suggested_unit_of_measurement': <UnitOfInformation.TEBIBYTES: 'TiB'>,
}),
}),
'original_device_class': <SensorDeviceClass.DATA_SIZE: 'data_size'>,
'original_icon': None,
'original_name': 'All-time download',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'alltime_download',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-alltime_download',
'unit_of_measurement': <UnitOfInformation.TEBIBYTES: 'TiB'>,
})
# ---
# name: test_entities[sensor.mock_title_all_time_download-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'data_size',
'friendly_name': 'Mock Title All-time download',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfInformation.TEBIBYTES: 'TiB'>,
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_all_time_download',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.783164386256431',
})
# ---
# name: test_entities[sensor.mock_title_all_time_upload-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_all_time_upload',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
'sensor.private': dict({
'suggested_unit_of_measurement': 'TiB',
}),
}),
'original_device_class': <SensorDeviceClass.DATA_SIZE: 'data_size'>,
'original_icon': None,
'original_name': 'All-time upload',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'alltime_upload',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-alltime_upload',
'unit_of_measurement': 'TiB',
})
# ---
# name: test_entities[sensor.mock_title_all_time_upload-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'data_size',
'friendly_name': 'Mock Title All-time upload',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'TiB',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_all_time_upload',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.659164934858381',
})
# ---
# name: test_entities[sensor.mock_title_all_torrents-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_all_torrents',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'All torrents',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'all_torrents',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-all_torrents',
'unit_of_measurement': 'torrents',
})
# ---
# name: test_entities[sensor.mock_title_all_torrents-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title All torrents',
'unit_of_measurement': 'torrents',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_all_torrents',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '6',
})
# ---
# name: test_entities[sensor.mock_title_connection_status-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'connected',
'firewalled',
'disconnected',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_connection_status',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Connection status',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'connection_status',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-connection_status',
'unit_of_measurement': None,
})
# ---
# name: test_entities[sensor.mock_title_connection_status-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Mock Title Connection status',
'options': list([
'connected',
'firewalled',
'disconnected',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_connection_status',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'connected',
})
# ---
# name: test_entities[sensor.mock_title_download_speed-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_download_speed',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
'sensor.private': dict({
'suggested_unit_of_measurement': <UnitOfDataRate.MEGABYTES_PER_SECOND: 'MB/s'>,
}),
}),
'original_device_class': <SensorDeviceClass.DATA_RATE: 'data_rate'>,
'original_icon': None,
'original_name': 'Download speed',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'download_speed',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-download_speed',
'unit_of_measurement': <UnitOfDataRate.MEGABYTES_PER_SECOND: 'MB/s'>,
})
# ---
# name: test_entities[sensor.mock_title_download_speed-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'data_rate',
'friendly_name': 'Mock Title Download speed',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfDataRate.MEGABYTES_PER_SECOND: 'MB/s'>,
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_download_speed',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.0',
})
# ---
# name: test_entities[sensor.mock_title_download_speed_limit-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_download_speed_limit',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
'sensor.private': dict({
'suggested_unit_of_measurement': <UnitOfDataRate.MEGABYTES_PER_SECOND: 'MB/s'>,
}),
}),
'original_device_class': <SensorDeviceClass.DATA_RATE: 'data_rate'>,
'original_icon': None,
'original_name': 'Download speed limit',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'download_speed_limit',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-download_speed_limit',
'unit_of_measurement': <UnitOfDataRate.MEGABYTES_PER_SECOND: 'MB/s'>,
})
# ---
# name: test_entities[sensor.mock_title_download_speed_limit-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'data_rate',
'friendly_name': 'Mock Title Download speed limit',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfDataRate.MEGABYTES_PER_SECOND: 'MB/s'>,
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_download_speed_limit',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.0',
})
# ---
# name: test_entities[sensor.mock_title_errored_torrents-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_errored_torrents',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Errored torrents',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'errored_torrents',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-errored_torrents',
'unit_of_measurement': 'torrents',
})
# ---
# name: test_entities[sensor.mock_title_errored_torrents-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Errored torrents',
'unit_of_measurement': 'torrents',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_errored_torrents',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2',
})
# ---
# name: test_entities[sensor.mock_title_global_ratio-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_global_ratio',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Global ratio',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'global_ratio',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-global_ratio',
'unit_of_measurement': None,
})
# ---
# name: test_entities[sensor.mock_title_global_ratio-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Global ratio',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_global_ratio',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.84',
})
# ---
# name: test_entities[sensor.mock_title_inactive_torrents-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_inactive_torrents',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Inactive torrents',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'inactive_torrents',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-inactive_torrents',
'unit_of_measurement': 'torrents',
})
# ---
# name: test_entities[sensor.mock_title_inactive_torrents-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Inactive torrents',
'unit_of_measurement': 'torrents',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_inactive_torrents',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2',
})
# ---
# name: test_entities[sensor.mock_title_paused_torrents-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_paused_torrents',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Paused torrents',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'paused_torrents',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-paused_torrents',
'unit_of_measurement': 'torrents',
})
# ---
# name: test_entities[sensor.mock_title_paused_torrents-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Paused torrents',
'unit_of_measurement': 'torrents',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_paused_torrents',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1',
})
# ---
# name: test_entities[sensor.mock_title_status-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'idle',
'up_down',
'seeding',
'downloading',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_status',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Status',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'current_status',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-current_status',
'unit_of_measurement': None,
})
# ---
# name: test_entities[sensor.mock_title_status-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Mock Title Status',
'options': list([
'idle',
'up_down',
'seeding',
'downloading',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_status',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'idle',
})
# ---
# name: test_entities[sensor.mock_title_upload_speed-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_upload_speed',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
'sensor.private': dict({
'suggested_unit_of_measurement': <UnitOfDataRate.MEGABYTES_PER_SECOND: 'MB/s'>,
}),
}),
'original_device_class': <SensorDeviceClass.DATA_RATE: 'data_rate'>,
'original_icon': None,
'original_name': 'Upload speed',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'upload_speed',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-upload_speed',
'unit_of_measurement': <UnitOfDataRate.MEGABYTES_PER_SECOND: 'MB/s'>,
})
# ---
# name: test_entities[sensor.mock_title_upload_speed-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'data_rate',
'friendly_name': 'Mock Title Upload speed',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfDataRate.MEGABYTES_PER_SECOND: 'MB/s'>,
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_upload_speed',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.0',
})
# ---
# name: test_entities[sensor.mock_title_upload_speed_limit-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_upload_speed_limit',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
'sensor.private': dict({
'suggested_unit_of_measurement': <UnitOfDataRate.MEGABYTES_PER_SECOND: 'MB/s'>,
}),
}),
'original_device_class': <SensorDeviceClass.DATA_RATE: 'data_rate'>,
'original_icon': None,
'original_name': 'Upload speed limit',
'platform': 'qbittorrent',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'upload_speed_limit',
'unique_id': '01K6E7464PTQKDE24VAJQZPTH2-upload_speed_limit',
'unit_of_measurement': <UnitOfDataRate.MEGABYTES_PER_SECOND: 'MB/s'>,
})
# ---
# name: test_entities[sensor.mock_title_upload_speed_limit-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'data_rate',
'friendly_name': 'Mock Title Upload speed limit',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfDataRate.MEGABYTES_PER_SECOND: 'MB/s'>,
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_upload_speed_limit',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.0',
})
# ---

View File

@@ -0,0 +1,29 @@
"""Tests for the qBittorrent sensor platform, including errored torrents."""
from unittest.mock import AsyncMock, patch
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
import homeassistant.helpers.entity_registry as er
from tests.common import MockConfigEntry, snapshot_platform
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_entities(
hass: HomeAssistant,
mock_qbittorrent: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test that sensors are created."""
with patch("homeassistant.components.qbittorrent.PLATFORMS", [Platform.SENSOR]):
mock_config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)