mirror of
https://github.com/home-assistant/core.git
synced 2026-03-13 06:22:03 +01:00
Compare commits
7 Commits
use-availa
...
yale-oauth
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f735b6042 | ||
|
|
9d962d3815 | ||
|
|
786fd40ae8 | ||
|
|
5ec65dbd58 | ||
|
|
35878bb203 | ||
|
|
e14d88ff55 | ||
|
|
d04efbfe48 |
@@ -8,7 +8,7 @@
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["pyenphase"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["pyenphase==2.4.5"],
|
||||
"requirements": ["pyenphase==2.4.6"],
|
||||
"zeroconf": [
|
||||
{
|
||||
"type": "_enphase-envoy._tcp.local."
|
||||
|
||||
@@ -5,7 +5,13 @@ from __future__ import annotations
|
||||
from functools import partial
|
||||
from typing import Any
|
||||
|
||||
from aioesphomeapi import EntityInfo, WaterHeaterInfo, WaterHeaterMode, WaterHeaterState
|
||||
from aioesphomeapi import (
|
||||
EntityInfo,
|
||||
WaterHeaterFeature,
|
||||
WaterHeaterInfo,
|
||||
WaterHeaterMode,
|
||||
WaterHeaterState,
|
||||
)
|
||||
|
||||
from homeassistant.components.water_heater import (
|
||||
WaterHeaterEntity,
|
||||
@@ -54,6 +60,7 @@ class EsphomeWaterHeater(
|
||||
static_info = self._static_info
|
||||
self._attr_min_temp = static_info.min_temperature
|
||||
self._attr_max_temp = static_info.max_temperature
|
||||
self._attr_target_temperature_step = static_info.target_temperature_step
|
||||
features = WaterHeaterEntityFeature.TARGET_TEMPERATURE
|
||||
if static_info.supported_modes:
|
||||
features |= WaterHeaterEntityFeature.OPERATION_MODE
|
||||
@@ -63,6 +70,8 @@ class EsphomeWaterHeater(
|
||||
]
|
||||
else:
|
||||
self._attr_operation_list = None
|
||||
if static_info.supported_features & WaterHeaterFeature.SUPPORTS_ON_OFF:
|
||||
features |= WaterHeaterEntityFeature.ON_OFF
|
||||
self._attr_supported_features = features
|
||||
|
||||
@property
|
||||
@@ -101,6 +110,24 @@ class EsphomeWaterHeater(
|
||||
device_id=self._static_info.device_id,
|
||||
)
|
||||
|
||||
@convert_api_error_ha_error
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the water heater on."""
|
||||
self._client.water_heater_command(
|
||||
key=self._key,
|
||||
on=True,
|
||||
device_id=self._static_info.device_id,
|
||||
)
|
||||
|
||||
@convert_api_error_ha_error
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the water heater off."""
|
||||
self._client.water_heater_command(
|
||||
key=self._key,
|
||||
on=False,
|
||||
device_id=self._static_info.device_id,
|
||||
)
|
||||
|
||||
|
||||
async_setup_entry = partial(
|
||||
platform_async_setup_entry,
|
||||
|
||||
@@ -21,5 +21,5 @@
|
||||
"integration_type": "system",
|
||||
"preview_features": { "winter_mode": {} },
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["home-assistant-frontend==20260304.0"]
|
||||
"requirements": ["home-assistant-frontend==20260312.0"]
|
||||
}
|
||||
|
||||
@@ -10,11 +10,7 @@ from functools import partial, wraps
|
||||
import logging
|
||||
from typing import Any, Concatenate
|
||||
|
||||
from aiohasupervisor import (
|
||||
AddonNotSupportedError,
|
||||
SupervisorError,
|
||||
SupervisorNotFoundError,
|
||||
)
|
||||
from aiohasupervisor import SupervisorError
|
||||
from aiohasupervisor.models import (
|
||||
AddonsOptions,
|
||||
AddonState as SupervisorAddonState,
|
||||
@@ -169,7 +165,15 @@ class AddonManager:
|
||||
)
|
||||
|
||||
addon_info = await self._supervisor_client.addons.addon_info(self.addon_slug)
|
||||
return self._async_convert_installed_addon_info(addon_info)
|
||||
addon_state = self.async_get_addon_state(addon_info)
|
||||
return AddonInfo(
|
||||
available=addon_info.available,
|
||||
hostname=addon_info.hostname,
|
||||
options=addon_info.options,
|
||||
state=addon_state,
|
||||
update_available=addon_info.update_available,
|
||||
version=addon_info.version,
|
||||
)
|
||||
|
||||
@callback
|
||||
def async_get_addon_state(self, addon_info: InstalledAddonComplete) -> AddonState:
|
||||
@@ -185,20 +189,6 @@ class AddonManager:
|
||||
|
||||
return addon_state
|
||||
|
||||
@callback
|
||||
def _async_convert_installed_addon_info(
|
||||
self, addon_info: InstalledAddonComplete
|
||||
) -> AddonInfo:
|
||||
"""Convert InstalledAddonComplete model to AddonInfo model."""
|
||||
return AddonInfo(
|
||||
available=addon_info.available,
|
||||
hostname=addon_info.hostname,
|
||||
options=addon_info.options,
|
||||
state=self.async_get_addon_state(addon_info),
|
||||
update_available=addon_info.update_available,
|
||||
version=addon_info.version,
|
||||
)
|
||||
|
||||
@api_error(
|
||||
"Failed to set the {addon_name} app options",
|
||||
expected_error_type=SupervisorError,
|
||||
@@ -209,17 +199,21 @@ class AddonManager:
|
||||
self.addon_slug, AddonsOptions(config=config)
|
||||
)
|
||||
|
||||
def _check_addon_available(self, addon_info: AddonInfo) -> None:
|
||||
"""Check if the managed add-on is available."""
|
||||
if not addon_info.available:
|
||||
raise AddonError(f"{self.addon_name} app is not available")
|
||||
|
||||
@api_error(
|
||||
"Failed to install the {addon_name} app", expected_error_type=SupervisorError
|
||||
)
|
||||
async def async_install_addon(self) -> None:
|
||||
"""Install the managed add-on."""
|
||||
try:
|
||||
await self._supervisor_client.store.install_addon(self.addon_slug)
|
||||
except AddonNotSupportedError as err:
|
||||
raise AddonError(
|
||||
f"{self.addon_name} app is not available: {err!s}"
|
||||
) from None
|
||||
addon_info = await self.async_get_addon_info()
|
||||
|
||||
self._check_addon_available(addon_info)
|
||||
|
||||
await self._supervisor_client.store.install_addon(self.addon_slug)
|
||||
|
||||
@api_error(
|
||||
"Failed to uninstall the {addon_name} app",
|
||||
@@ -232,29 +226,17 @@ class AddonManager:
|
||||
@api_error("Failed to update the {addon_name} app")
|
||||
async def async_update_addon(self) -> None:
|
||||
"""Update the managed add-on if needed."""
|
||||
try:
|
||||
# Not using async_get_addon_info here because it would make an unnecessary
|
||||
# call to /store/addon/{slug}/info. This will raise if the addon is not
|
||||
# installed so one call to /addon/{slug}/info is all that is needed
|
||||
addon_info = await self._supervisor_client.addons.addon_info(
|
||||
self.addon_slug
|
||||
)
|
||||
except SupervisorNotFoundError:
|
||||
raise AddonError(f"{self.addon_name} app is not installed") from None
|
||||
addon_info = await self.async_get_addon_info()
|
||||
|
||||
self._check_addon_available(addon_info)
|
||||
|
||||
if addon_info.state is AddonState.NOT_INSTALLED:
|
||||
raise AddonError(f"{self.addon_name} app is not installed")
|
||||
|
||||
if not addon_info.update_available:
|
||||
return
|
||||
|
||||
try:
|
||||
await self._supervisor_client.store.addon_availability(self.addon_slug)
|
||||
except AddonNotSupportedError as err:
|
||||
raise AddonError(
|
||||
f"{self.addon_name} app is not available: {err!s}"
|
||||
) from None
|
||||
|
||||
await self.async_create_backup(
|
||||
addon_info=self._async_convert_installed_addon_info(addon_info)
|
||||
)
|
||||
await self.async_create_backup()
|
||||
await self._supervisor_client.store.update_addon(
|
||||
self.addon_slug, StoreAddonUpdate(backup=False)
|
||||
)
|
||||
@@ -284,14 +266,10 @@ class AddonManager:
|
||||
"Failed to create a backup of the {addon_name} app",
|
||||
expected_error_type=SupervisorError,
|
||||
)
|
||||
async def async_create_backup(self, *, addon_info: AddonInfo | None = None) -> None:
|
||||
async def async_create_backup(self) -> None:
|
||||
"""Create a partial backup of the managed add-on."""
|
||||
if addon_info:
|
||||
addon_version = addon_info.version
|
||||
else:
|
||||
addon_version = (await self.async_get_addon_info()).version
|
||||
|
||||
name = f"addon_{self.addon_slug}_{addon_version}"
|
||||
addon_info = await self.async_get_addon_info()
|
||||
name = f"addon_{self.addon_slug}_{addon_info.version}"
|
||||
|
||||
self._logger.debug("Creating backup: %s", name)
|
||||
await self._supervisor_client.backups.partial_backup(
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["onedrive_personal_sdk"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["onedrive-personal-sdk==0.1.6"]
|
||||
"requirements": ["onedrive-personal-sdk==0.1.7"]
|
||||
}
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["onedrive_personal_sdk"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["onedrive-personal-sdk==0.1.6"]
|
||||
"requirements": ["onedrive-personal-sdk==0.1.7"]
|
||||
}
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/portainer",
|
||||
"integration_type": "service",
|
||||
"iot_class": "local_polling",
|
||||
"quality_scale": "bronze",
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["pyportainer==1.0.33"]
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
from pathlib import Path
|
||||
from typing import cast
|
||||
|
||||
from aiohttp import ClientResponseError
|
||||
from aiohttp import ClientError
|
||||
from yalexs.const import Brand
|
||||
from yalexs.exceptions import YaleApiError
|
||||
from yalexs.manager.const import CONF_BRAND
|
||||
@@ -15,7 +15,12 @@ from yalexs.manager.gateway import Config as YaleXSConfig
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
from homeassistant.exceptions import (
|
||||
ConfigEntryAuthFailed,
|
||||
ConfigEntryNotReady,
|
||||
OAuth2TokenRequestError,
|
||||
OAuth2TokenRequestReauthError,
|
||||
)
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.config_entry_oauth2_flow import (
|
||||
ImplementationUnavailableError,
|
||||
@@ -42,11 +47,18 @@ async def async_setup_entry(hass: HomeAssistant, entry: YaleConfigEntry) -> bool
|
||||
yale_gateway = YaleGateway(Path(hass.config.config_dir), session, oauth_session)
|
||||
try:
|
||||
await async_setup_yale(hass, entry, yale_gateway)
|
||||
except OAuth2TokenRequestReauthError as err:
|
||||
raise ConfigEntryAuthFailed from err
|
||||
except (RequireValidation, InvalidAuth) as err:
|
||||
raise ConfigEntryAuthFailed from err
|
||||
except TimeoutError as err:
|
||||
raise ConfigEntryNotReady("Timed out connecting to yale api") from err
|
||||
except (YaleApiError, ClientResponseError, CannotConnect) as err:
|
||||
except (
|
||||
YaleApiError,
|
||||
OAuth2TokenRequestError,
|
||||
ClientError,
|
||||
CannotConnect,
|
||||
) as err:
|
||||
raise ConfigEntryNotReady from err
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
return True
|
||||
|
||||
@@ -40,7 +40,7 @@ habluetooth==5.9.1
|
||||
hass-nabucasa==2.0.0
|
||||
hassil==3.5.0
|
||||
home-assistant-bluetooth==1.13.1
|
||||
home-assistant-frontend==20260304.0
|
||||
home-assistant-frontend==20260312.0
|
||||
home-assistant-intents==2026.3.3
|
||||
httpx==0.28.1
|
||||
ifaddr==0.2.0
|
||||
|
||||
6
requirements_all.txt
generated
6
requirements_all.txt
generated
@@ -1223,7 +1223,7 @@ hole==0.9.0
|
||||
holidays==0.84
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20260304.0
|
||||
home-assistant-frontend==20260312.0
|
||||
|
||||
# homeassistant.components.conversation
|
||||
home-assistant-intents==2026.3.3
|
||||
@@ -1676,7 +1676,7 @@ ondilo==0.5.0
|
||||
|
||||
# homeassistant.components.onedrive
|
||||
# homeassistant.components.onedrive_for_business
|
||||
onedrive-personal-sdk==0.1.6
|
||||
onedrive-personal-sdk==0.1.7
|
||||
|
||||
# homeassistant.components.onvif
|
||||
onvif-zeep-async==4.0.4
|
||||
@@ -2071,7 +2071,7 @@ pyegps==0.2.5
|
||||
pyemoncms==0.1.3
|
||||
|
||||
# homeassistant.components.enphase_envoy
|
||||
pyenphase==2.4.5
|
||||
pyenphase==2.4.6
|
||||
|
||||
# homeassistant.components.envisalink
|
||||
pyenvisalink==4.7
|
||||
|
||||
6
requirements_test_all.txt
generated
6
requirements_test_all.txt
generated
@@ -1084,7 +1084,7 @@ hole==0.9.0
|
||||
holidays==0.84
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20260304.0
|
||||
home-assistant-frontend==20260312.0
|
||||
|
||||
# homeassistant.components.conversation
|
||||
home-assistant-intents==2026.3.3
|
||||
@@ -1462,7 +1462,7 @@ ondilo==0.5.0
|
||||
|
||||
# homeassistant.components.onedrive
|
||||
# homeassistant.components.onedrive_for_business
|
||||
onedrive-personal-sdk==0.1.6
|
||||
onedrive-personal-sdk==0.1.7
|
||||
|
||||
# homeassistant.components.onvif
|
||||
onvif-zeep-async==4.0.4
|
||||
@@ -1775,7 +1775,7 @@ pyegps==0.2.5
|
||||
pyemoncms==0.1.3
|
||||
|
||||
# homeassistant.components.enphase_envoy
|
||||
pyenphase==2.4.5
|
||||
pyenphase==2.4.6
|
||||
|
||||
# homeassistant.components.everlights
|
||||
pyeverlights==0.1.0
|
||||
|
||||
@@ -44,12 +44,14 @@ def state_1_fixture(client: Mock) -> State:
|
||||
state.zn = 1
|
||||
state.get_power.return_value = True
|
||||
state.get_volume.return_value = 0.0
|
||||
state.get_source.return_value = None
|
||||
state.get_source_list.return_value = []
|
||||
state.get_incoming_audio_format.return_value = (None, None)
|
||||
state.get_incoming_video_parameters.return_value = None
|
||||
state.get_incoming_audio_sample_rate.return_value = 0
|
||||
state.get_mute.return_value = None
|
||||
state.get_decode_modes.return_value = []
|
||||
state.get_decode_mode.return_value = None
|
||||
return state
|
||||
|
||||
|
||||
@@ -61,12 +63,14 @@ def state_2_fixture(client: Mock) -> State:
|
||||
state.zn = 2
|
||||
state.get_power.return_value = True
|
||||
state.get_volume.return_value = 0.0
|
||||
state.get_source.return_value = None
|
||||
state.get_source_list.return_value = []
|
||||
state.get_incoming_audio_format.return_value = (None, None)
|
||||
state.get_incoming_video_parameters.return_value = None
|
||||
state.get_incoming_audio_sample_rate.return_value = 0
|
||||
state.get_mute.return_value = None
|
||||
state.get_decode_modes.return_value = []
|
||||
state.get_decode_mode.return_value = None
|
||||
return state
|
||||
|
||||
|
||||
@@ -90,7 +94,7 @@ async def player_setup_fixture(
|
||||
state_1: State,
|
||||
state_2: State,
|
||||
client: Mock,
|
||||
) -> AsyncGenerator[str]:
|
||||
) -> AsyncGenerator[None]:
|
||||
"""Get standard player."""
|
||||
|
||||
def state_mock(cli, zone):
|
||||
@@ -101,7 +105,15 @@ async def player_setup_fixture(
|
||||
raise ValueError(f"Unknown player zone: {zone}")
|
||||
|
||||
async def _mock_run_client(hass: HomeAssistant, runtime_data, interval):
|
||||
for coordinator in runtime_data.coordinators.values():
|
||||
coordinators = runtime_data.coordinators
|
||||
|
||||
def _notify_data_updated() -> None:
|
||||
for coordinator in coordinators.values():
|
||||
coordinator.async_notify_data_updated()
|
||||
|
||||
client.notify_data_updated = _notify_data_updated
|
||||
|
||||
for coordinator in coordinators.values():
|
||||
coordinator.async_notify_connected()
|
||||
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
@@ -119,4 +131,4 @@ async def player_setup_fixture(
|
||||
):
|
||||
assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
yield MOCK_ENTITY_ID
|
||||
yield
|
||||
|
||||
105
tests/components/arcam_fmj/snapshots/test_media_player.ambr
Normal file
105
tests/components/arcam_fmj/snapshots/test_media_player.ambr
Normal file
@@ -0,0 +1,105 @@
|
||||
# serializer version: 1
|
||||
# name: test_setup[media_player.arcam_fmj_127_0_0_1_zone_1-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'media_player',
|
||||
'entity_category': None,
|
||||
'entity_id': 'media_player.arcam_fmj_127_0_0_1_zone_1',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Zone 1',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Zone 1',
|
||||
'platform': 'arcam_fmj',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': <MediaPlayerEntityFeature: 200588>,
|
||||
'translation_key': None,
|
||||
'unique_id': '456789abcdef-1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[media_player.arcam_fmj_127_0_0_1_zone_1-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Arcam FMJ (127.0.0.1) Zone 1',
|
||||
'supported_features': <MediaPlayerEntityFeature: 200588>,
|
||||
'volume_level': 0.0,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.arcam_fmj_127_0_0_1_zone_1',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[media_player.arcam_fmj_127_0_0_1_zone_2_zone_2-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'media_player',
|
||||
'entity_category': None,
|
||||
'entity_id': 'media_player.arcam_fmj_127_0_0_1_zone_2_zone_2',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Zone 2',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Zone 2',
|
||||
'platform': 'arcam_fmj',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': <MediaPlayerEntityFeature: 135052>,
|
||||
'translation_key': None,
|
||||
'unique_id': '456789abcdef-2',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[media_player.arcam_fmj_127_0_0_1_zone_2_zone_2-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Arcam FMJ (127.0.0.1) Zone 2 Zone 2',
|
||||
'supported_features': <MediaPlayerEntityFeature: 135052>,
|
||||
'volume_level': 0.0,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.arcam_fmj_127_0_0_1_zone_2_zone_2',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
@@ -9,6 +9,8 @@ from homeassistant.core import HomeAssistant, ServiceCall
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .conftest import MOCK_ENTITY_ID
|
||||
|
||||
from tests.common import MockConfigEntry, async_get_device_automations
|
||||
|
||||
|
||||
@@ -59,7 +61,7 @@ async def test_if_fires_on_turn_on_request(
|
||||
state_1: State,
|
||||
) -> None:
|
||||
"""Test for turn_on and turn_off triggers firing."""
|
||||
entry = entity_registry.async_get(player_setup)
|
||||
entry = entity_registry.async_get(MOCK_ENTITY_ID)
|
||||
|
||||
state_1.get_power.return_value = None
|
||||
|
||||
@@ -91,13 +93,13 @@ async def test_if_fires_on_turn_on_request(
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
"turn_on",
|
||||
{"entity_id": player_setup},
|
||||
{"entity_id": MOCK_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert len(service_calls) == 2
|
||||
assert service_calls[1].data["some"] == player_setup
|
||||
assert service_calls[1].data["some"] == MOCK_ENTITY_ID
|
||||
assert service_calls[1].data["id"] == 0
|
||||
|
||||
|
||||
@@ -109,7 +111,7 @@ async def test_if_fires_on_turn_on_request_legacy(
|
||||
state_1: State,
|
||||
) -> None:
|
||||
"""Test for turn_on and turn_off triggers firing."""
|
||||
entry = entity_registry.async_get(player_setup)
|
||||
entry = entity_registry.async_get(MOCK_ENTITY_ID)
|
||||
|
||||
state_1.get_power.return_value = None
|
||||
|
||||
@@ -141,11 +143,11 @@ async def test_if_fires_on_turn_on_request_legacy(
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
"turn_on",
|
||||
{"entity_id": player_setup},
|
||||
{"entity_id": MOCK_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert len(service_calls) == 2
|
||||
assert service_calls[1].data["some"] == player_setup
|
||||
assert service_calls[1].data["some"] == MOCK_ENTITY_ID
|
||||
assert service_calls[1].data["id"] == 0
|
||||
|
||||
@@ -6,6 +6,7 @@ from unittest.mock import Mock, PropertyMock, patch
|
||||
from arcam.fmj import ConnectionFailed, DecodeMode2CH, DecodeModeMCH, SourceCodes
|
||||
from arcam.fmj.state import State
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.arcam_fmj.media_player import ArcamFmj
|
||||
from homeassistant.components.homeassistant import (
|
||||
@@ -14,145 +15,146 @@ from homeassistant.components.homeassistant import (
|
||||
)
|
||||
from homeassistant.components.media_player import (
|
||||
ATTR_INPUT_SOURCE,
|
||||
ATTR_MEDIA_ARTIST,
|
||||
ATTR_MEDIA_CHANNEL,
|
||||
ATTR_MEDIA_CONTENT_TYPE,
|
||||
ATTR_MEDIA_VOLUME_LEVEL,
|
||||
ATTR_MEDIA_VOLUME_MUTED,
|
||||
ATTR_SOUND_MODE,
|
||||
ATTR_SOUND_MODE_LIST,
|
||||
DATA_COMPONENT,
|
||||
DOMAIN as MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_SELECT_SOUND_MODE,
|
||||
SERVICE_SELECT_SOURCE,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
SERVICE_VOLUME_DOWN,
|
||||
SERVICE_VOLUME_MUTE,
|
||||
SERVICE_VOLUME_SET,
|
||||
SERVICE_VOLUME_UP,
|
||||
MediaType,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_IDENTIFIERS,
|
||||
ATTR_MANUFACTURER,
|
||||
ATTR_MODEL,
|
||||
ATTR_NAME,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||
from homeassistant.core import HomeAssistant, State as CoreState
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from .conftest import MOCK_ENTITY_ID, MOCK_HOST, MOCK_UUID
|
||||
from .conftest import MOCK_ENTITY_ID
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
MOCK_TURN_ON = {
|
||||
"service": "switch.turn_on",
|
||||
"data": {"entity_id": "switch.test"},
|
||||
}
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
|
||||
@pytest.fixture(name="player")
|
||||
def player_fixture(
|
||||
@pytest.fixture(autouse=True)
|
||||
def platform_fixture():
|
||||
"""Only test single platform."""
|
||||
with patch("homeassistant.components.arcam_fmj.PLATFORMS", [Platform.MEDIA_PLAYER]):
|
||||
yield
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_setup(
|
||||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
client: Mock,
|
||||
state_1: State,
|
||||
player_setup: str,
|
||||
) -> ArcamFmj:
|
||||
"""Get standard player.
|
||||
|
||||
This fixture tests internals and should not be used going forward.
|
||||
"""
|
||||
player: ArcamFmj = hass.data[DATA_COMPONENT].get_entity(MOCK_ENTITY_ID)
|
||||
player.async_write_ha_state = Mock(wraps=player.async_write_ha_state)
|
||||
return player
|
||||
|
||||
|
||||
async def update(player: ArcamFmj, force_refresh=False):
|
||||
"""Force a update of player and return current state data."""
|
||||
await player.async_update_ha_state(force_refresh=force_refresh)
|
||||
return player.hass.states.get(player.entity_id)
|
||||
|
||||
|
||||
async def test_properties(player: ArcamFmj) -> None:
|
||||
"""Test standard properties."""
|
||||
assert player.unique_id == f"{MOCK_UUID}-1"
|
||||
assert player.device_info == {
|
||||
ATTR_NAME: f"Arcam FMJ ({MOCK_HOST})",
|
||||
ATTR_IDENTIFIERS: {
|
||||
("arcam_fmj", MOCK_UUID),
|
||||
},
|
||||
ATTR_MODEL: "Arcam FMJ AVR",
|
||||
ATTR_MANUFACTURER: "Arcam",
|
||||
}
|
||||
assert not player.should_poll
|
||||
|
||||
|
||||
async def test_powered_off(
|
||||
hass: HomeAssistant, player: ArcamFmj, state_1: State
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test setup creates expected entities."""
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
async def update(hass: HomeAssistant, client: Mock, entity_id: str) -> CoreState:
|
||||
"""Force a update of player and return current state data."""
|
||||
client.notify_data_updated()
|
||||
await hass.async_block_till_done()
|
||||
data = hass.states.get(entity_id)
|
||||
assert data
|
||||
return data
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_powered_off(hass: HomeAssistant, client: Mock, state_1: State) -> None:
|
||||
"""Test properties in powered off state."""
|
||||
state_1.get_source.return_value = None
|
||||
state_1.get_power.return_value = None
|
||||
|
||||
data = await update(player)
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert "source" not in data.attributes
|
||||
assert data.state == "off"
|
||||
|
||||
|
||||
async def test_powered_on(player: ArcamFmj, state_1: State) -> None:
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_powered_on(hass: HomeAssistant, client: Mock, state_1: State) -> None:
|
||||
"""Test properties in powered on state."""
|
||||
state_1.get_source.return_value = SourceCodes.PVR
|
||||
state_1.get_power.return_value = True
|
||||
|
||||
data = await update(player)
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert data.attributes["source"] == "PVR"
|
||||
assert data.state == "on"
|
||||
|
||||
|
||||
async def test_supported_features(player: ArcamFmj) -> None:
|
||||
"""Test supported features."""
|
||||
data = await update(player)
|
||||
assert data.attributes["supported_features"] == 200588
|
||||
|
||||
|
||||
async def test_turn_on(player: ArcamFmj, state_1: State) -> None:
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_turn_on(hass: HomeAssistant, state_1: State) -> None:
|
||||
"""Test turn on service."""
|
||||
state_1.get_power.return_value = None
|
||||
await player.async_turn_on()
|
||||
await hass.services.async_call(
|
||||
MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
service_data={ATTR_ENTITY_ID: MOCK_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
state_1.set_power.assert_not_called()
|
||||
|
||||
state_1.get_power.return_value = False
|
||||
await player.async_turn_on()
|
||||
await hass.services.async_call(
|
||||
MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
service_data={ATTR_ENTITY_ID: MOCK_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
state_1.set_power.assert_called_with(True)
|
||||
|
||||
|
||||
async def test_turn_off(player: ArcamFmj, state_1: State) -> None:
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_turn_off(hass: HomeAssistant, state_1: State) -> None:
|
||||
"""Test command to turn off."""
|
||||
await player.async_turn_off()
|
||||
await hass.services.async_call(
|
||||
MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
service_data={ATTR_ENTITY_ID: MOCK_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
state_1.set_power.assert_called_with(False)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mute", [True, False])
|
||||
async def test_mute_volume(player: ArcamFmj, state_1: State, mute: bool) -> None:
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_mute_volume(hass: HomeAssistant, state_1: State, mute: bool) -> None:
|
||||
"""Test mute functionality."""
|
||||
player.async_write_ha_state.reset_mock()
|
||||
await player.async_mute_volume(mute)
|
||||
await hass.services.async_call(
|
||||
MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_VOLUME_MUTE,
|
||||
service_data={ATTR_ENTITY_ID: MOCK_ENTITY_ID, ATTR_MEDIA_VOLUME_MUTED: mute},
|
||||
blocking=True,
|
||||
)
|
||||
state_1.set_mute.assert_called_with(mute)
|
||||
player.async_write_ha_state.assert_called_with()
|
||||
|
||||
|
||||
async def test_name(player: ArcamFmj) -> None:
|
||||
"""Test name."""
|
||||
data = await update(player)
|
||||
assert data.attributes["friendly_name"] == "Arcam FMJ (127.0.0.1) Zone 1"
|
||||
|
||||
|
||||
async def test_update(hass: HomeAssistant, player_setup: str, state_1: State) -> None:
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_update(hass: HomeAssistant, state_1: State) -> None:
|
||||
"""Test update."""
|
||||
await hass.services.async_call(
|
||||
HA_DOMAIN,
|
||||
SERVICE_UPDATE_ENTITY,
|
||||
service_data={ATTR_ENTITY_ID: player_setup},
|
||||
service_data={ATTR_ENTITY_ID: MOCK_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
state_1.update.assert_called_with()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_update_lost(
|
||||
hass: HomeAssistant,
|
||||
player_setup: str,
|
||||
state_1: State,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
@@ -162,7 +164,7 @@ async def test_update_lost(
|
||||
await hass.services.async_call(
|
||||
HA_DOMAIN,
|
||||
SERVICE_UPDATE_ENTITY,
|
||||
service_data={ATTR_ENTITY_ID: player_setup},
|
||||
service_data={ATTR_ENTITY_ID: MOCK_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
state_1.update.assert_called_with()
|
||||
@@ -172,9 +174,9 @@ async def test_update_lost(
|
||||
("source", "value"),
|
||||
[("PVR", SourceCodes.PVR), ("BD", SourceCodes.BD), ("INVALID", None)],
|
||||
)
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_select_source(
|
||||
hass: HomeAssistant,
|
||||
player_setup,
|
||||
state_1: State,
|
||||
source: str,
|
||||
value: SourceCodes | None,
|
||||
@@ -183,7 +185,7 @@ async def test_select_source(
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
SERVICE_SELECT_SOURCE,
|
||||
service_data={ATTR_ENTITY_ID: player_setup, ATTR_INPUT_SOURCE: source},
|
||||
service_data={ATTR_ENTITY_ID: MOCK_ENTITY_ID, ATTR_INPUT_SOURCE: source},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
@@ -193,10 +195,11 @@ async def test_select_source(
|
||||
state_1.set_source.assert_not_called()
|
||||
|
||||
|
||||
async def test_source_list(player: ArcamFmj, state_1: State) -> None:
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_source_list(hass: HomeAssistant, client: Mock, state_1: State) -> None:
|
||||
"""Test source list."""
|
||||
state_1.get_source_list.return_value = [SourceCodes.BD]
|
||||
data = await update(player)
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert data.attributes["source_list"] == ["BD"]
|
||||
|
||||
|
||||
@@ -207,26 +210,42 @@ async def test_source_list(player: ArcamFmj, state_1: State) -> None:
|
||||
"DOLBY_PL",
|
||||
],
|
||||
)
|
||||
async def test_select_sound_mode(player: ArcamFmj, state_1: State, mode: str) -> None:
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_select_sound_mode(
|
||||
hass: HomeAssistant, state_1: State, mode: str
|
||||
) -> None:
|
||||
"""Test selection sound mode."""
|
||||
await player.async_select_sound_mode(mode)
|
||||
await hass.services.async_call(
|
||||
MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_SELECT_SOUND_MODE,
|
||||
service_data={ATTR_ENTITY_ID: MOCK_ENTITY_ID, ATTR_SOUND_MODE: mode},
|
||||
blocking=True,
|
||||
)
|
||||
state_1.set_decode_mode.assert_called_with(mode)
|
||||
|
||||
|
||||
async def test_volume_up(player: ArcamFmj, state_1: State) -> None:
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_volume_up(hass: HomeAssistant, state_1: State) -> None:
|
||||
"""Test mute functionality."""
|
||||
player.async_write_ha_state.reset_mock()
|
||||
await player.async_volume_up()
|
||||
await hass.services.async_call(
|
||||
MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_VOLUME_UP,
|
||||
service_data={ATTR_ENTITY_ID: MOCK_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
state_1.inc_volume.assert_called_with()
|
||||
player.async_write_ha_state.assert_called_with()
|
||||
|
||||
|
||||
async def test_volume_down(player: ArcamFmj, state_1: State) -> None:
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_volume_down(hass: HomeAssistant, state_1: State) -> None:
|
||||
"""Test mute functionality."""
|
||||
player.async_write_ha_state.reset_mock()
|
||||
await player.async_volume_down()
|
||||
await hass.services.async_call(
|
||||
MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_VOLUME_DOWN,
|
||||
service_data={ATTR_ENTITY_ID: MOCK_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
state_1.dec_volume.assert_called_with()
|
||||
player.async_write_ha_state.assert_called_with()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -237,10 +256,13 @@ async def test_volume_down(player: ArcamFmj, state_1: State) -> None:
|
||||
(None, None),
|
||||
],
|
||||
)
|
||||
async def test_sound_mode(player: ArcamFmj, state_1: State, mode, mode_enum) -> None:
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_sound_mode(
|
||||
hass: HomeAssistant, client: Mock, state_1: State, mode, mode_enum
|
||||
) -> None:
|
||||
"""Test selection sound mode."""
|
||||
state_1.get_decode_mode.return_value = mode_enum
|
||||
data = await update(player)
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert data.attributes.get(ATTR_SOUND_MODE) == mode
|
||||
|
||||
|
||||
@@ -252,56 +274,73 @@ async def test_sound_mode(player: ArcamFmj, state_1: State, mode, mode_enum) ->
|
||||
(None, None),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_sound_mode_list(
|
||||
player: ArcamFmj, state_1: State, modes, modes_enum
|
||||
hass: HomeAssistant, client: Mock, state_1: State, modes, modes_enum
|
||||
) -> None:
|
||||
"""Test sound mode list."""
|
||||
state_1.get_decode_modes.return_value = modes_enum
|
||||
data = await update(player)
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert data.attributes.get(ATTR_SOUND_MODE_LIST) == modes
|
||||
|
||||
|
||||
async def test_is_volume_muted(player: ArcamFmj, state_1: State) -> None:
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_is_volume_muted(
|
||||
hass: HomeAssistant, client: Mock, state_1: State
|
||||
) -> None:
|
||||
"""Test muted."""
|
||||
state_1.get_mute.return_value = True
|
||||
assert player.is_volume_muted is True
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert data.attributes.get(ATTR_MEDIA_VOLUME_MUTED) is True
|
||||
|
||||
state_1.get_mute.return_value = False
|
||||
assert player.is_volume_muted is False
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert data.attributes.get(ATTR_MEDIA_VOLUME_MUTED) is False
|
||||
|
||||
state_1.get_mute.return_value = None
|
||||
assert player.is_volume_muted is None
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert data.attributes.get(ATTR_MEDIA_VOLUME_MUTED) is None
|
||||
|
||||
|
||||
async def test_volume_level(player: ArcamFmj, state_1: State) -> None:
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_volume_level(hass: HomeAssistant, client: Mock, state_1: State) -> None:
|
||||
"""Test volume."""
|
||||
state_1.get_volume.return_value = 0
|
||||
assert isclose(player.volume_level, 0.0)
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert isclose(data.attributes[ATTR_MEDIA_VOLUME_LEVEL], 0.0)
|
||||
|
||||
state_1.get_volume.return_value = 50
|
||||
assert isclose(player.volume_level, 50.0 / 99)
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert isclose(data.attributes[ATTR_MEDIA_VOLUME_LEVEL], 50.0 / 99)
|
||||
|
||||
state_1.get_volume.return_value = 99
|
||||
assert isclose(player.volume_level, 1.0)
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert isclose(data.attributes[ATTR_MEDIA_VOLUME_LEVEL], 1.0)
|
||||
|
||||
state_1.get_volume.return_value = None
|
||||
assert player.volume_level is None
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert ATTR_MEDIA_VOLUME_LEVEL not in data.attributes
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("volume", "call"), [(0.0, 0), (0.5, 50), (1.0, 99)])
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_set_volume_level(
|
||||
hass: HomeAssistant, player_setup: str, state_1: State, volume, call
|
||||
hass: HomeAssistant, state_1: State, volume, call
|
||||
) -> None:
|
||||
"""Test setting volume."""
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
SERVICE_VOLUME_SET,
|
||||
service_data={ATTR_ENTITY_ID: player_setup, ATTR_MEDIA_VOLUME_LEVEL: volume},
|
||||
service_data={ATTR_ENTITY_ID: MOCK_ENTITY_ID, ATTR_MEDIA_VOLUME_LEVEL: volume},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
state_1.set_volume.assert_called_with(call)
|
||||
|
||||
|
||||
async def test_set_volume_level_lost(
|
||||
hass: HomeAssistant, player_setup: str, state_1: State
|
||||
) -> None:
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_set_volume_level_lost(hass: HomeAssistant, state_1: State) -> None:
|
||||
"""Test setting volume, with a lost connection."""
|
||||
|
||||
state_1.set_volume.side_effect = ConnectionFailed()
|
||||
@@ -310,7 +349,7 @@ async def test_set_volume_level_lost(
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
SERVICE_VOLUME_SET,
|
||||
service_data={ATTR_ENTITY_ID: player_setup, ATTR_MEDIA_VOLUME_LEVEL: 0.0},
|
||||
service_data={ATTR_ENTITY_ID: MOCK_ENTITY_ID, ATTR_MEDIA_VOLUME_LEVEL: 0.0},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
@@ -324,12 +363,14 @@ async def test_set_volume_level_lost(
|
||||
(None, None),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_media_content_type(
|
||||
player: ArcamFmj, state_1: State, source, media_content_type
|
||||
hass: HomeAssistant, client: Mock, state_1: State, source, media_content_type
|
||||
) -> None:
|
||||
"""Test content type deduction."""
|
||||
state_1.get_source.return_value = source
|
||||
assert player.media_content_type == media_content_type
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert data.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == media_content_type
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -342,14 +383,16 @@ async def test_media_content_type(
|
||||
(SourceCodes.PVR, "dab", "rds", None),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_media_channel(
|
||||
player: ArcamFmj, state_1: State, source, dab, rds, channel
|
||||
hass: HomeAssistant, client: Mock, state_1: State, source, dab, rds, channel
|
||||
) -> None:
|
||||
"""Test media channel."""
|
||||
state_1.get_dab_station.return_value = dab
|
||||
state_1.get_rds_information.return_value = rds
|
||||
state_1.get_source.return_value = source
|
||||
assert player.media_channel == channel
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert data.attributes.get(ATTR_MEDIA_CHANNEL) == channel
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -360,13 +403,15 @@ async def test_media_channel(
|
||||
(SourceCodes.DAB, None, None),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_media_artist(
|
||||
player: ArcamFmj, state_1: State, source, dls, artist
|
||||
hass: HomeAssistant, client: Mock, state_1: State, source, dls, artist
|
||||
) -> None:
|
||||
"""Test media artist."""
|
||||
state_1.get_dls_pdt.return_value = dls
|
||||
state_1.get_source.return_value = source
|
||||
assert player.media_artist == artist
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
assert data.attributes.get(ATTR_MEDIA_ARTIST) == artist
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -377,8 +422,9 @@ async def test_media_artist(
|
||||
(None, None, None),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("player_setup")
|
||||
async def test_media_title(
|
||||
player: ArcamFmj, state_1: State, source, channel, title
|
||||
hass: HomeAssistant, client: Mock, state_1: State, source, channel, title
|
||||
) -> None:
|
||||
"""Test media title."""
|
||||
|
||||
@@ -387,7 +433,7 @@ async def test_media_title(
|
||||
ArcamFmj, "media_channel", new_callable=PropertyMock
|
||||
) as media_channel:
|
||||
media_channel.return_value = channel
|
||||
data = await update(player)
|
||||
data = await update(hass, client, MOCK_ENTITY_ID)
|
||||
if title is None:
|
||||
assert "media_title" not in data.attributes
|
||||
else:
|
||||
|
||||
@@ -13,7 +13,6 @@ import string
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from aiohasupervisor import SupervisorNotFoundError
|
||||
from aiohasupervisor.models import (
|
||||
Discovery,
|
||||
GreenInfo,
|
||||
@@ -314,7 +313,6 @@ def addon_not_installed_fixture(
|
||||
"""Mock add-on not installed."""
|
||||
from .hassio.common import mock_addon_not_installed # noqa: PLC0415
|
||||
|
||||
addon_info.side_effect = SupervisorNotFoundError
|
||||
return mock_addon_not_installed(addon_store_info, addon_info)
|
||||
|
||||
|
||||
|
||||
@@ -2,13 +2,22 @@
|
||||
|
||||
from unittest.mock import call
|
||||
|
||||
from aioesphomeapi import APIClient, WaterHeaterInfo, WaterHeaterMode, WaterHeaterState
|
||||
from aioesphomeapi import (
|
||||
APIClient,
|
||||
WaterHeaterFeature,
|
||||
WaterHeaterInfo,
|
||||
WaterHeaterMode,
|
||||
WaterHeaterState,
|
||||
)
|
||||
|
||||
from homeassistant.components.water_heater import (
|
||||
ATTR_OPERATION_LIST,
|
||||
DOMAIN as WATER_HEATER_DOMAIN,
|
||||
SERVICE_SET_OPERATION_MODE,
|
||||
SERVICE_SET_TEMPERATURE,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
WaterHeaterEntityFeature,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -183,3 +192,130 @@ async def test_water_heater_set_operation_mode(
|
||||
mock_client.water_heater_command.assert_has_calls(
|
||||
[call(key=1, mode=WaterHeaterMode.GAS, device_id=0)]
|
||||
)
|
||||
|
||||
|
||||
async def test_water_heater_on_off(
|
||||
hass: HomeAssistant,
|
||||
mock_client: APIClient,
|
||||
mock_generic_device_entry: MockGenericDeviceEntryType,
|
||||
) -> None:
|
||||
"""Test turning the water heater on and off."""
|
||||
entity_info = [
|
||||
WaterHeaterInfo(
|
||||
object_id="my_boiler",
|
||||
key=1,
|
||||
name="My Boiler",
|
||||
min_temperature=10.0,
|
||||
max_temperature=85.0,
|
||||
supported_features=WaterHeaterFeature.SUPPORTS_ON_OFF,
|
||||
)
|
||||
]
|
||||
states = [
|
||||
WaterHeaterState(
|
||||
key=1,
|
||||
target_temperature=50.0,
|
||||
)
|
||||
]
|
||||
|
||||
await mock_generic_device_entry(
|
||||
mock_client=mock_client,
|
||||
entity_info=entity_info,
|
||||
states=states,
|
||||
)
|
||||
|
||||
state = hass.states.get("water_heater.test_my_boiler")
|
||||
assert state is not None
|
||||
assert state.attributes["supported_features"] & WaterHeaterEntityFeature.ON_OFF
|
||||
|
||||
await hass.services.async_call(
|
||||
WATER_HEATER_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "water_heater.test_my_boiler"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mock_client.water_heater_command.assert_has_calls(
|
||||
[call(key=1, on=True, device_id=0)]
|
||||
)
|
||||
|
||||
mock_client.water_heater_command.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
WATER_HEATER_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: "water_heater.test_my_boiler"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mock_client.water_heater_command.assert_has_calls(
|
||||
[call(key=1, on=False, device_id=0)]
|
||||
)
|
||||
|
||||
|
||||
async def test_water_heater_target_temperature_step(
|
||||
hass: HomeAssistant,
|
||||
mock_client: APIClient,
|
||||
mock_generic_device_entry: MockGenericDeviceEntryType,
|
||||
) -> None:
|
||||
"""Test target temperature step is respected."""
|
||||
entity_info = [
|
||||
WaterHeaterInfo(
|
||||
object_id="my_boiler",
|
||||
key=1,
|
||||
name="My Boiler",
|
||||
min_temperature=10.0,
|
||||
max_temperature=85.0,
|
||||
target_temperature_step=5.0,
|
||||
)
|
||||
]
|
||||
states = [
|
||||
WaterHeaterState(
|
||||
key=1,
|
||||
target_temperature=50.0,
|
||||
)
|
||||
]
|
||||
|
||||
await mock_generic_device_entry(
|
||||
mock_client=mock_client,
|
||||
entity_info=entity_info,
|
||||
states=states,
|
||||
)
|
||||
|
||||
state = hass.states.get("water_heater.test_my_boiler")
|
||||
assert state is not None
|
||||
assert state.attributes["target_temp_step"] == 5.0
|
||||
|
||||
|
||||
async def test_water_heater_no_on_off_without_feature(
|
||||
hass: HomeAssistant,
|
||||
mock_client: APIClient,
|
||||
mock_generic_device_entry: MockGenericDeviceEntryType,
|
||||
) -> None:
|
||||
"""Test ON_OFF feature is not set when not supported."""
|
||||
entity_info = [
|
||||
WaterHeaterInfo(
|
||||
object_id="my_boiler",
|
||||
key=1,
|
||||
name="My Boiler",
|
||||
min_temperature=10.0,
|
||||
max_temperature=85.0,
|
||||
)
|
||||
]
|
||||
states = [
|
||||
WaterHeaterState(
|
||||
key=1,
|
||||
target_temperature=50.0,
|
||||
)
|
||||
]
|
||||
|
||||
await mock_generic_device_entry(
|
||||
mock_client=mock_client,
|
||||
entity_info=entity_info,
|
||||
states=states,
|
||||
)
|
||||
|
||||
state = hass.states.get("water_heater.test_my_boiler")
|
||||
assert state is not None
|
||||
assert not (
|
||||
state.attributes["supported_features"] & WaterHeaterEntityFeature.ON_OFF
|
||||
)
|
||||
|
||||
@@ -3,15 +3,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock, call
|
||||
from uuid import uuid4
|
||||
|
||||
from aiohasupervisor import (
|
||||
AddonNotSupportedArchitectureError,
|
||||
AddonNotSupportedHomeAssistantVersionError,
|
||||
AddonNotSupportedMachineTypeError,
|
||||
SupervisorError,
|
||||
)
|
||||
from aiohasupervisor import SupervisorError
|
||||
from aiohasupervisor.models import AddonsOptions, Discovery, PartialBackupOptions
|
||||
import pytest
|
||||
|
||||
@@ -24,8 +20,10 @@ from homeassistant.components.hassio.addon_manager import (
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("addon_not_installed")
|
||||
async def test_not_installed_raises_exception(addon_manager: AddonManager) -> None:
|
||||
async def test_not_installed_raises_exception(
|
||||
addon_manager: AddonManager,
|
||||
addon_not_installed: dict[str, Any],
|
||||
) -> None:
|
||||
"""Test addon not installed raises exception."""
|
||||
addon_config = {"test_key": "test"}
|
||||
|
||||
@@ -40,40 +38,24 @@ async def test_not_installed_raises_exception(addon_manager: AddonManager) -> No
|
||||
assert str(err.value) == "Test app is not installed"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"exception",
|
||||
[
|
||||
AddonNotSupportedArchitectureError(
|
||||
"Add-on test not supported on this platform, supported architectures: test"
|
||||
),
|
||||
AddonNotSupportedHomeAssistantVersionError(
|
||||
"Add-on test not supported on this system, requires Home Assistant version 2026.1.0 or greater"
|
||||
),
|
||||
AddonNotSupportedMachineTypeError(
|
||||
"Add-on test not supported on this machine, supported machine types: test"
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_not_available_raises_exception(
|
||||
addon_manager: AddonManager,
|
||||
supervisor_client: AsyncMock,
|
||||
addon_store_info: AsyncMock,
|
||||
addon_info: AsyncMock,
|
||||
exception: SupervisorError,
|
||||
) -> None:
|
||||
"""Test addon not available raises exception."""
|
||||
supervisor_client.store.addon_availability.side_effect = exception
|
||||
supervisor_client.store.install_addon.side_effect = exception
|
||||
addon_info.return_value.update_available = True
|
||||
addon_store_info.return_value.available = False
|
||||
addon_info.return_value.available = False
|
||||
|
||||
with pytest.raises(AddonError) as err:
|
||||
await addon_manager.async_install_addon()
|
||||
|
||||
assert str(err.value) == f"Test app is not available: {exception!s}"
|
||||
assert str(err.value) == "Test app is not available"
|
||||
|
||||
with pytest.raises(AddonError) as err:
|
||||
await addon_manager.async_update_addon()
|
||||
|
||||
assert str(err.value) == f"Test app is not available: {exception!s}"
|
||||
assert str(err.value) == "Test app is not available"
|
||||
|
||||
|
||||
async def test_get_addon_discovery_info(
|
||||
@@ -514,10 +496,11 @@ async def test_stop_addon_error(
|
||||
assert stop_addon.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("hass", "addon_installed")
|
||||
async def test_update_addon(
|
||||
hass: HomeAssistant,
|
||||
addon_manager: AddonManager,
|
||||
addon_info: AsyncMock,
|
||||
addon_installed: AsyncMock,
|
||||
create_backup: AsyncMock,
|
||||
update_addon: AsyncMock,
|
||||
) -> None:
|
||||
@@ -526,7 +509,7 @@ async def test_update_addon(
|
||||
|
||||
await addon_manager.async_update_addon()
|
||||
|
||||
assert addon_info.call_count == 1
|
||||
assert addon_info.call_count == 2
|
||||
assert create_backup.call_count == 1
|
||||
assert create_backup.call_args == call(
|
||||
PartialBackupOptions(name="addon_test_addon_1.0.0", addons={"test_addon"})
|
||||
@@ -534,10 +517,10 @@ async def test_update_addon(
|
||||
assert update_addon.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("addon_installed")
|
||||
async def test_update_addon_no_update(
|
||||
addon_manager: AddonManager,
|
||||
addon_info: AsyncMock,
|
||||
addon_installed: AsyncMock,
|
||||
create_backup: AsyncMock,
|
||||
update_addon: AsyncMock,
|
||||
) -> None:
|
||||
@@ -551,10 +534,11 @@ async def test_update_addon_no_update(
|
||||
assert update_addon.call_count == 0
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("hass", "addon_installed")
|
||||
async def test_update_addon_error(
|
||||
hass: HomeAssistant,
|
||||
addon_manager: AddonManager,
|
||||
addon_info: AsyncMock,
|
||||
addon_installed: AsyncMock,
|
||||
create_backup: AsyncMock,
|
||||
update_addon: AsyncMock,
|
||||
) -> None:
|
||||
@@ -567,7 +551,7 @@ async def test_update_addon_error(
|
||||
|
||||
assert str(err.value) == "Failed to update the Test app: Boom"
|
||||
|
||||
assert addon_info.call_count == 1
|
||||
assert addon_info.call_count == 2
|
||||
assert create_backup.call_count == 1
|
||||
assert create_backup.call_args == call(
|
||||
PartialBackupOptions(name="addon_test_addon_1.0.0", addons={"test_addon"})
|
||||
@@ -575,10 +559,11 @@ async def test_update_addon_error(
|
||||
assert update_addon.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("hass", "addon_installed")
|
||||
async def test_schedule_update_addon(
|
||||
hass: HomeAssistant,
|
||||
addon_manager: AddonManager,
|
||||
addon_info: AsyncMock,
|
||||
addon_installed: AsyncMock,
|
||||
create_backup: AsyncMock,
|
||||
update_addon: AsyncMock,
|
||||
) -> None:
|
||||
@@ -604,7 +589,7 @@ async def test_schedule_update_addon(
|
||||
await asyncio.gather(update_task, update_task_two)
|
||||
|
||||
assert addon_manager.task_in_progress() is False
|
||||
assert addon_info.call_count == 2
|
||||
assert addon_info.call_count == 3
|
||||
assert create_backup.call_count == 1
|
||||
assert create_backup.call_args == call(
|
||||
PartialBackupOptions(name="addon_test_addon_1.0.0", addons={"test_addon"})
|
||||
|
||||
@@ -906,6 +906,7 @@ async def test_config_flow_thread_addon_already_installed(
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("addon_not_installed")
|
||||
async def test_options_flow_zigbee_to_thread(
|
||||
hass: HomeAssistant,
|
||||
install_addon: AsyncMock,
|
||||
|
||||
@@ -445,15 +445,17 @@ async def test_zeroconf_not_onboarded_installed(
|
||||
]
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("supervisor", "addon_not_installed", "not_onboarded")
|
||||
async def test_zeroconf_not_onboarded_not_installed(
|
||||
hass: HomeAssistant,
|
||||
supervisor: MagicMock,
|
||||
addon_info: AsyncMock,
|
||||
addon_store_info: AsyncMock,
|
||||
addon_not_installed: AsyncMock,
|
||||
install_addon: AsyncMock,
|
||||
start_addon: AsyncMock,
|
||||
client_connect: AsyncMock,
|
||||
setup_entry: AsyncMock,
|
||||
not_onboarded: MagicMock,
|
||||
zeroconf_info: ZeroconfServiceInfo,
|
||||
) -> None:
|
||||
"""Test flow Zeroconf discovery when not onboarded and add-on not installed."""
|
||||
@@ -465,7 +467,7 @@ async def test_zeroconf_not_onboarded_not_installed(
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert addon_info.call_count == 0
|
||||
assert addon_store_info.call_count == 1
|
||||
assert addon_store_info.call_count == 2
|
||||
assert install_addon.call_args == call("core_matter_server")
|
||||
assert start_addon.call_args == call("core_matter_server")
|
||||
assert client_connect.call_count == 1
|
||||
|
||||
@@ -258,7 +258,10 @@ async def test_listen_failure_config_entry_loaded(
|
||||
|
||||
|
||||
async def test_raise_addon_task_in_progress(
|
||||
hass: HomeAssistant, install_addon: AsyncMock, start_addon: AsyncMock
|
||||
hass: HomeAssistant,
|
||||
addon_not_installed: AsyncMock,
|
||||
install_addon: AsyncMock,
|
||||
start_addon: AsyncMock,
|
||||
) -> None:
|
||||
"""Test raise ConfigEntryNotReady if an add-on task is in progress."""
|
||||
install_event = asyncio.Event()
|
||||
@@ -334,6 +337,7 @@ async def test_start_addon(
|
||||
|
||||
async def test_install_addon(
|
||||
hass: HomeAssistant,
|
||||
addon_not_installed: AsyncMock,
|
||||
addon_store_info: AsyncMock,
|
||||
install_addon: AsyncMock,
|
||||
start_addon: AsyncMock,
|
||||
@@ -353,7 +357,7 @@ async def test_install_addon(
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.state is ConfigEntryState.SETUP_RETRY
|
||||
assert addon_store_info.call_count == 2
|
||||
assert addon_store_info.call_count == 3
|
||||
assert install_addon.call_count == 1
|
||||
assert install_addon.call_args == call("core_matter_server")
|
||||
assert start_addon.call_count == 1
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from aiohttp import ClientResponseError
|
||||
from aiohttp import ClientError, ClientResponseError
|
||||
import pytest
|
||||
from yalexs.exceptions import InvalidAuth, YaleApiError
|
||||
|
||||
@@ -17,7 +17,11 @@ from homeassistant.const import (
|
||||
STATE_ON,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.exceptions import (
|
||||
HomeAssistantError,
|
||||
OAuth2TokenRequestReauthError,
|
||||
OAuth2TokenRequestTransientError,
|
||||
)
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers.config_entry_oauth2_flow import (
|
||||
ImplementationUnavailableError,
|
||||
@@ -254,3 +258,58 @@ async def test_oauth_implementation_not_available(hass: HomeAssistant) -> None:
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.state is ConfigEntryState.SETUP_RETRY
|
||||
|
||||
|
||||
async def test_oauth_token_request_reauth_error(hass: HomeAssistant) -> None:
|
||||
"""Test OAuth token request reauth error starts a reauth flow."""
|
||||
entry = await mock_yale_config_entry(hass)
|
||||
|
||||
with patch(
|
||||
"homeassistant.helpers.config_entry_oauth2_flow.OAuth2Session.async_ensure_token_valid",
|
||||
side_effect=OAuth2TokenRequestReauthError(
|
||||
request_info=Mock(real_url="https://auth.yale.com/access_token"),
|
||||
status=401,
|
||||
domain=DOMAIN,
|
||||
),
|
||||
):
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.state is ConfigEntryState.SETUP_ERROR
|
||||
flows = hass.config_entries.flow.async_progress()
|
||||
assert len(flows) == 1
|
||||
assert flows[0]["context"]["source"] == "reauth"
|
||||
|
||||
|
||||
async def test_oauth_token_request_transient_error_is_retryable(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test OAuth token transient request error marks entry for setup retry."""
|
||||
entry = await mock_yale_config_entry(hass)
|
||||
|
||||
with patch(
|
||||
"homeassistant.helpers.config_entry_oauth2_flow.OAuth2Session.async_ensure_token_valid",
|
||||
side_effect=OAuth2TokenRequestTransientError(
|
||||
request_info=Mock(real_url="https://auth.yale.com/access_token"),
|
||||
status=500,
|
||||
domain=DOMAIN,
|
||||
),
|
||||
):
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.state is ConfigEntryState.SETUP_RETRY
|
||||
|
||||
|
||||
async def test_oauth_client_error_is_retryable(hass: HomeAssistant) -> None:
|
||||
"""Test OAuth transport client errors mark entry for setup retry."""
|
||||
entry = await mock_yale_config_entry(hass)
|
||||
|
||||
with patch(
|
||||
"homeassistant.helpers.config_entry_oauth2_flow.OAuth2Session.async_ensure_token_valid",
|
||||
side_effect=ClientError("connection error"),
|
||||
):
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.state is ConfigEntryState.SETUP_RETRY
|
||||
|
||||
@@ -651,7 +651,7 @@ async def test_abort_hassio_discovery_for_other_addon(hass: HomeAssistant) -> No
|
||||
assert result2["reason"] == "not_zwave_js_addon"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("supervisor", "addon_info")
|
||||
@pytest.mark.usefixtures("supervisor", "addon_not_installed", "addon_info")
|
||||
@pytest.mark.parametrize(
|
||||
("usb_discovery_info", "device", "discovery_name"),
|
||||
[
|
||||
@@ -1176,7 +1176,7 @@ async def test_usb_discovery_migration_restore_driver_ready_timeout(
|
||||
@pytest.mark.parametrize(
|
||||
"service_info", [ESPHOME_DISCOVERY_INFO, ESPHOME_DISCOVERY_INFO_CLEAN]
|
||||
)
|
||||
@pytest.mark.usefixtures("supervisor", "addon_info")
|
||||
@pytest.mark.usefixtures("supervisor", "addon_not_installed", "addon_info")
|
||||
async def test_esphome_discovery_intent_custom(
|
||||
hass: HomeAssistant,
|
||||
install_addon: AsyncMock,
|
||||
@@ -1460,7 +1460,7 @@ async def test_esphome_discovery_already_configured_unmanaged_addon(
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("supervisor", "addon_info")
|
||||
@pytest.mark.usefixtures("supervisor", "addon_not_installed", "addon_info")
|
||||
async def test_esphome_discovery_usb_same_home_id(
|
||||
hass: HomeAssistant,
|
||||
install_addon: AsyncMock,
|
||||
@@ -1699,7 +1699,7 @@ async def test_discovery_addon_not_running(
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("supervisor", "addon_info")
|
||||
@pytest.mark.usefixtures("supervisor", "addon_not_installed", "addon_info")
|
||||
async def test_discovery_addon_not_installed(
|
||||
hass: HomeAssistant,
|
||||
install_addon: AsyncMock,
|
||||
@@ -2768,7 +2768,7 @@ async def test_addon_installed_already_configured(
|
||||
assert entry.data["lr_s2_authenticated_key"] == "new321"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("supervisor", "addon_info")
|
||||
@pytest.mark.usefixtures("supervisor", "addon_not_installed", "addon_info")
|
||||
async def test_addon_not_installed(
|
||||
hass: HomeAssistant,
|
||||
install_addon: AsyncMock,
|
||||
@@ -3873,7 +3873,7 @@ async def test_reconfigure_addon_running_server_info_failure(
|
||||
assert client.disconnect.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("supervisor")
|
||||
@pytest.mark.usefixtures("supervisor", "addon_not_installed")
|
||||
@pytest.mark.parametrize(
|
||||
(
|
||||
"entry_data",
|
||||
@@ -5036,7 +5036,7 @@ async def test_get_usb_ports_ignored_devices() -> None:
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("supervisor", "addon_info")
|
||||
@pytest.mark.usefixtures("supervisor", "addon_not_installed", "addon_info")
|
||||
async def test_intent_recommended_user(
|
||||
hass: HomeAssistant,
|
||||
install_addon: AsyncMock,
|
||||
@@ -5132,7 +5132,7 @@ async def test_intent_recommended_user(
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("supervisor", "addon_info")
|
||||
@pytest.mark.usefixtures("supervisor", "addon_not_installed", "addon_info")
|
||||
@pytest.mark.parametrize(
|
||||
("usb_discovery_info", "device", "discovery_name"),
|
||||
[
|
||||
|
||||
@@ -933,7 +933,7 @@ async def test_start_addon(
|
||||
assert start_addon.call_args == call("core_zwave_js")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("addon_info")
|
||||
@pytest.mark.usefixtures("addon_not_installed", "addon_info")
|
||||
async def test_install_addon(
|
||||
hass: HomeAssistant,
|
||||
install_addon: AsyncMock,
|
||||
|
||||
Reference in New Issue
Block a user