mirror of
https://github.com/home-assistant/core.git
synced 2026-05-19 06:50:15 +01:00
Fix line length violations in tests/components t-z (#170994)
This commit is contained in:
@@ -124,7 +124,7 @@ async def test_duration_enabled_without_tado_default(
|
||||
async def test_duration_enabled_with_tado_default(
|
||||
hass: HomeAssistant, entry: ConfigEntry, tado: Tado
|
||||
) -> None:
|
||||
"""Test overlay method selection when ended up with timer overlay and None duration."""
|
||||
"""Test overlay method selection with timer overlay and None duration."""
|
||||
zone_fallback = CONST_OVERLAY_TIMER
|
||||
expected_duration = 45000
|
||||
tado = dummy_tado_connector(
|
||||
|
||||
@@ -59,7 +59,7 @@ DEFAULT_CONFIG = {
|
||||
"20": 0, # Update of Dimmer/Color/CT without turning power on
|
||||
"30": 0, # Enforce Home Assistant auto-discovery as light
|
||||
"68": 0, # Multi-channel PWM instead of a single light
|
||||
"73": 0, # Enable Buttons decoupling and send multi-press and hold MQTT messages
|
||||
"73": 0, # Enable Buttons decoupling and send multi-press
|
||||
"82": 0, # Reduce the CT range from 153..500 to 200.380
|
||||
"114": 0, # Enable sending switch MQTT messages
|
||||
},
|
||||
@@ -94,7 +94,7 @@ DEFAULT_CONFIG_9_0_0_3 = {
|
||||
"20": 0, # Update of Dimmer/Color/CT without turning power on
|
||||
"30": 0, # Enforce Home Assistant auto-discovery as light
|
||||
"68": 0, # Multi-channel PWM instead of a single light
|
||||
"73": 0, # Enable Buttons decoupling and send multi-press and hold MQTT messages
|
||||
"73": 0, # Enable Buttons decoupling and send multi-press
|
||||
"80": 0, # Blinds and shutters support
|
||||
"82": 0, # Reduce the CT range from 153..500 to 200.380
|
||||
},
|
||||
|
||||
@@ -30,8 +30,10 @@ async def test_mqtt_abort_invalid_topic(
|
||||
discovery_info = MqttServiceInfo(
|
||||
topic="tasmota/discovery/DC4F220848A2/bla",
|
||||
payload=(
|
||||
'{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,'
|
||||
'null,null,null],"hn":"tasmota_0848A2","mac":"DC4F220848A2","md":"Sonoff Basic",'
|
||||
'{"ip":"192.168.0.136","dn":"Tasmota",'
|
||||
'"fn":["Tasmota",null,null,null,null,'
|
||||
'null,null,null],"hn":"tasmota_0848A2",'
|
||||
'"mac":"DC4F220848A2","md":"Sonoff Basic",'
|
||||
'"ty":0,"if":0,"ofln":"Offline","onln":"Online","state":["OFF","ON",'
|
||||
'"TOGGLE","HOLD"],"sw":"9.4.0.4","t":"tasmota_0848A2","ft":"%topic%/%prefix%/",'
|
||||
'"tp":["cmnd","stat","tele"],"rl":[1,0,0,0,0,0,0,0],"swc":[-1,-1,-1,-1,-1,-1,-1,-1],'
|
||||
@@ -67,8 +69,10 @@ async def test_mqtt_abort_invalid_topic(
|
||||
discovery_info = MqttServiceInfo(
|
||||
topic="tasmota/discovery/DC4F220848A2/config",
|
||||
payload=(
|
||||
'{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,'
|
||||
'null,null,null],"hn":"tasmota_0848A2","mac":"DC4F220848A2","md":"Sonoff Basic",'
|
||||
'{"ip":"192.168.0.136","dn":"Tasmota",'
|
||||
'"fn":["Tasmota",null,null,null,null,'
|
||||
'null,null,null],"hn":"tasmota_0848A2",'
|
||||
'"mac":"DC4F220848A2","md":"Sonoff Basic",'
|
||||
'"ty":0,"if":0,"ofln":"Offline","onln":"Online","state":["OFF","ON",'
|
||||
'"TOGGLE","HOLD"],"sw":"9.4.0.4","t":"tasmota_0848A2","ft":"%topic%/%prefix%/",'
|
||||
'"tp":["cmnd","stat","tele"],"rl":[1,0,0,0,0,0,0,0],"swc":[-1,-1,-1,-1,-1,-1,-1,-1],'
|
||||
@@ -92,8 +96,10 @@ async def test_mqtt_setup(hass: HomeAssistant, mqtt_mock: MqttMockHAClient) -> N
|
||||
discovery_info = MqttServiceInfo(
|
||||
topic="tasmota/discovery/DC4F220848A2/config",
|
||||
payload=(
|
||||
'{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,'
|
||||
'null,null,null],"hn":"tasmota_0848A2","mac":"DC4F220848A2","md":"Sonoff Basic",'
|
||||
'{"ip":"192.168.0.136","dn":"Tasmota",'
|
||||
'"fn":["Tasmota",null,null,null,null,'
|
||||
'null,null,null],"hn":"tasmota_0848A2",'
|
||||
'"mac":"DC4F220848A2","md":"Sonoff Basic",'
|
||||
'"ty":0,"if":0,"ofln":"Offline","onln":"Online","state":["OFF","ON",'
|
||||
'"TOGGLE","HOLD"],"sw":"9.4.0.4","t":"tasmota_0848A2","ft":"%topic%/%prefix%/",'
|
||||
'"tp":["cmnd","stat","tele"],"rl":[1,0,0,0,0,0,0,0],"swc":[-1,-1,-1,-1,-1,-1,-1,-1],'
|
||||
|
||||
@@ -400,7 +400,8 @@ async def test_device_remove_multiple_config_entries_2(
|
||||
assert device_entry.config_entries == {tasmota_entry.entry_id}
|
||||
mqtt_mock.async_publish.assert_not_called()
|
||||
|
||||
# Remove other config entry from the other device - Tasmota should not do any cleanup
|
||||
# Remove other config entry from the other device
|
||||
# Tasmota should not do any cleanup
|
||||
device_registry.async_update_device(
|
||||
other_device_entry.id, remove_config_entry_id=mock_entry.entry_id
|
||||
)
|
||||
|
||||
@@ -188,7 +188,8 @@ async def test_sending_mqtt_commands(
|
||||
assert state.attributes["percentage"] == 0
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
|
||||
# Finally, turn the fan on again and verify MQTT message is sent with last known speed
|
||||
# Finally, turn the fan on again and verify MQTT message is sent
|
||||
# with last known speed
|
||||
await common.async_turn_on(hass, "fan.tasmota")
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"tasmota_49A3BC/cmnd/FanSpeed", "3", 0, False, message_expiry_interval=None
|
||||
|
||||
@@ -201,7 +201,8 @@ TEMPERATURE_SENSOR_CONFIG = {
|
||||
["sensor.tasmota_tx23_speed_act", "sensor.tasmota_tx23_dir_card"],
|
||||
(
|
||||
'{"TX23":{"Speed":{"Act":"12.3"},"Dir": {"Card": "WSW"}}}',
|
||||
'{"StatusSNS":{"TX23":{"Speed":{"Act":"23.4"},"Dir": {"Card": "ESE"}}}}',
|
||||
'{"StatusSNS":{"TX23":{"Speed":{"Act":"23.4"},'
|
||||
'"Dir": {"Card": "ESE"}}}}',
|
||||
),
|
||||
),
|
||||
(
|
||||
@@ -239,8 +240,10 @@ TEMPERATURE_SENSOR_CONFIG = {
|
||||
LIST_SENSOR_CONFIG_2,
|
||||
["sensor.tasmota_energy_total_0", "sensor.tasmota_energy_total_1"],
|
||||
(
|
||||
'{"ENERGY":{"Total":[1.2, 3.4],"TotalStartTime":"2018-11-23T15:33:47"}}',
|
||||
'{"StatusSNS":{"ENERGY":{"Total":[5.6, 7.8],"TotalStartTime":"2018-11-23T16:33:47"}}}',
|
||||
'{"ENERGY":{"Total":[1.2, 3.4],'
|
||||
'"TotalStartTime":"2018-11-23T15:33:47"}}',
|
||||
'{"StatusSNS":{"ENERGY":{"Total":[5.6, 7.8],'
|
||||
'"TotalStartTime":"2018-11-23T16:33:47"}}}',
|
||||
),
|
||||
),
|
||||
# Test dict Total sensors
|
||||
@@ -251,8 +254,11 @@ TEMPERATURE_SENSOR_CONFIG = {
|
||||
"sensor.tasmota_energy_total_phase2",
|
||||
],
|
||||
(
|
||||
'{"ENERGY":{"Total":{"Phase1":1.2, "Phase2":3.4},"TotalStartTime":"2018-11-23T15:33:47"}}',
|
||||
'{"StatusSNS":{"ENERGY":{"Total":{"Phase1":5.6, "Phase2":7.8},"TotalStartTime":"2018-11-23T15:33:47"}}}',
|
||||
'{"ENERGY":{"Total":{"Phase1":1.2, "Phase2":3.4},'
|
||||
'"TotalStartTime":"2018-11-23T15:33:47"}}',
|
||||
'{"StatusSNS":{"ENERGY":'
|
||||
'{"Total":{"Phase1":5.6, "Phase2":7.8},'
|
||||
'"TotalStartTime":"2018-11-23T15:33:47"}}}',
|
||||
),
|
||||
),
|
||||
(
|
||||
@@ -292,7 +298,8 @@ TEMPERATURE_SENSOR_CONFIG = {
|
||||
),
|
||||
),
|
||||
),
|
||||
# Test we automatically set state class to measurement on unknown numerical sensors
|
||||
# Test we automatically set state class to measurement on
|
||||
# unknown numerical sensors
|
||||
(
|
||||
DEFAULT_SENSOR_CONFIG_UNKNOWN,
|
||||
[
|
||||
|
||||
@@ -75,7 +75,7 @@ async def test_connection_error(hass: HomeAssistant, mock_technove: MagicMock) -
|
||||
async def test_full_user_flow_with_error(
|
||||
hass: HomeAssistant, mock_technove: MagicMock
|
||||
) -> None:
|
||||
"""Test the full manual user flow from start to finish with some errors in the middle."""
|
||||
"""Test the full manual user flow with some errors in the middle."""
|
||||
mock_technove.update.side_effect = TechnoVEConnectionError
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
|
||||
@@ -134,7 +134,10 @@ async def test_lock_without_pullspring(
|
||||
|
||||
with pytest.raises(
|
||||
ServiceNotSupported,
|
||||
match=f"Entity lock.lock_2c3d does not support action {LOCK_DOMAIN}.{SERVICE_OPEN}",
|
||||
match=(
|
||||
"Entity lock.lock_2c3d does not support action"
|
||||
f" {LOCK_DOMAIN}.{SERVICE_OPEN}"
|
||||
),
|
||||
):
|
||||
await hass.services.async_call(
|
||||
LOCK_DOMAIN,
|
||||
|
||||
@@ -255,7 +255,7 @@ def update_message_text():
|
||||
|
||||
@pytest.fixture
|
||||
def unauthorized_update_message_text(update_message_text):
|
||||
"""Fixture for mocking an incoming update of type message/text that is not in our `allowed_chat_ids`."""
|
||||
"""Fixture for mocking an incoming unauthorized message/text."""
|
||||
update_message_text["message"]["from"]["id"] = 1234
|
||||
update_message_text["message"]["chat"]["id"] = 1234
|
||||
return update_message_text
|
||||
@@ -285,7 +285,7 @@ def update_callback_query():
|
||||
|
||||
@pytest.fixture
|
||||
def update_callback_inline_keyboard():
|
||||
"""Fixture for mocking an incoming update of type callback_query from inline keyboard button."""
|
||||
"""Fixture for mocking a callback_query from inline keyboard."""
|
||||
return {
|
||||
"update_id": 1,
|
||||
"callback_query": {
|
||||
@@ -382,7 +382,7 @@ async def webhook_bot(
|
||||
|
||||
@pytest.fixture
|
||||
def mock_polling_calls() -> Generator[None]:
|
||||
"""Fixture for setting up the polling platform using appropriate config and mocks."""
|
||||
"""Fixture for setting up the polling platform with config and mocks."""
|
||||
with patch(
|
||||
"homeassistant.components.telegram_bot.polling.ApplicationBuilder"
|
||||
) as application_builder_class:
|
||||
|
||||
@@ -743,7 +743,7 @@ async def test_subentry_flow_broadcast_update_error(
|
||||
mock_broadcast_config_entry: MockConfigEntry,
|
||||
mock_external_calls: None,
|
||||
) -> None:
|
||||
"""Test subentry flow where broadcast bot encounter error while receiving messages."""
|
||||
"""Test subentry flow where broadcast bot errors receiving messages."""
|
||||
|
||||
mock_broadcast_config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(mock_broadcast_config_entry.entry_id)
|
||||
|
||||
@@ -205,7 +205,7 @@ async def test_polling_platform_init_failed(
|
||||
async def test_send_message(
|
||||
hass: HomeAssistant, webhook_bot, service: str, input: dict[str, Any]
|
||||
) -> None:
|
||||
"""Test the send_message service. Tests any service that does not require files to be sent."""
|
||||
"""Test services that do not require files to be sent."""
|
||||
context = Context()
|
||||
events = async_capture_events(hass, "telegram_sent")
|
||||
|
||||
@@ -375,7 +375,12 @@ async def test_send_sticker_partial_error(
|
||||
assert mock_send_sticker.call_count == 2
|
||||
assert err.value.translation_key == "multiple_errors"
|
||||
assert err.value.translation_placeholders == {
|
||||
"errors": "`entity_id` notify.mock_title_mock_chat_1: mock network error\n`entity_id` notify.mock_title_mock_chat_2: mock network error"
|
||||
"errors": (
|
||||
"`entity_id` notify.mock_title_mock_chat_1:"
|
||||
" mock network error\n"
|
||||
"`entity_id` notify.mock_title_mock_chat_2:"
|
||||
" mock network error"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -623,7 +628,7 @@ async def test_webhook_endpoint_generates_telegram_text_event(
|
||||
update_message_text,
|
||||
mock_generate_secret_token,
|
||||
) -> None:
|
||||
"""POST to the configured webhook endpoint and assert fired `telegram_text` event."""
|
||||
"""POST to webhook endpoint and assert fired telegram_text event."""
|
||||
client = await hass_client()
|
||||
events = async_capture_events(hass, "telegram_text")
|
||||
|
||||
@@ -650,7 +655,7 @@ async def test_webhook_endpoint_generates_telegram_command_event(
|
||||
update_message_command,
|
||||
mock_generate_secret_token,
|
||||
) -> None:
|
||||
"""POST to the configured webhook endpoint and assert fired `telegram_command` event."""
|
||||
"""POST to webhook endpoint and assert fired telegram_command event."""
|
||||
client = await hass_client()
|
||||
events = async_capture_events(hass, "telegram_command")
|
||||
|
||||
@@ -752,7 +757,7 @@ async def test_webhook_endpoint_generates_telegram_attachment_event(
|
||||
mock_generate_secret_token: str,
|
||||
attachment_type: str,
|
||||
) -> None:
|
||||
"""POST to the configured webhook endpoint and assert fired `telegram_attachment` event for photo and document."""
|
||||
"""POST to webhook and assert fired telegram_attachment event."""
|
||||
client = await hass_client()
|
||||
events = async_capture_events(hass, "telegram_attachment")
|
||||
update_message_attachment = await async_load_fixture(
|
||||
@@ -790,13 +795,14 @@ async def test_polling_platform_message_text_update(
|
||||
update_message_text,
|
||||
mock_external_calls: None,
|
||||
) -> None:
|
||||
"""Provide the `BaseTelegramBot.update_handler` with an `Update` and assert fired `telegram_text` event."""
|
||||
"""Test update_handler with an Update fires telegram_text event."""
|
||||
events = async_capture_events(hass, "telegram_text")
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.telegram_bot.polling.ApplicationBuilder"
|
||||
) as application_builder_class:
|
||||
# Set up the integration with the polling platform inside the patch context manager.
|
||||
# Set up the integration with the polling platform inside
|
||||
# the patch context manager.
|
||||
application = (
|
||||
application_builder_class.return_value.bot.return_value.build.return_value
|
||||
)
|
||||
@@ -1941,10 +1947,24 @@ async def test_migrate_chat_id(
|
||||
"action": "telegram_bot.send_message",
|
||||
"action_origin": expected_action_origin,
|
||||
"chat_ids": "654321",
|
||||
"telegram_bot_entities_url": "/config/entities?domain=telegram_bot",
|
||||
"example_old": "```yaml\naction: send_message\ndata:\n target: # to be updated\n - 1234567890\n...\n```",
|
||||
"example_new_entity_id": "```yaml\naction: send_message\ndata:\n entity_id:\n - notify.telegram_bot_1234567890_1234567890 # replace with your notify entity\n...\n```",
|
||||
"example_new_chat_id": "```yaml\naction: send_message\ndata:\n chat_id:\n - 1234567890 # replace with your chat_id\n...\n```",
|
||||
"telegram_bot_entities_url": ("/config/entities?domain=telegram_bot"),
|
||||
"example_old": (
|
||||
"```yaml\naction: send_message\ndata:\n"
|
||||
" target: # to be updated\n"
|
||||
" - 1234567890\n...\n```"
|
||||
),
|
||||
"example_new_entity_id": (
|
||||
"```yaml\naction: send_message\ndata:\n"
|
||||
" entity_id:\n"
|
||||
" - notify.telegram_bot_1234567890_1234567890"
|
||||
" # replace with your notify entity\n...\n```"
|
||||
),
|
||||
"example_new_chat_id": (
|
||||
"```yaml\naction: send_message\ndata:\n"
|
||||
" chat_id:\n"
|
||||
" - 1234567890"
|
||||
" # replace with your chat_id\n...\n```"
|
||||
),
|
||||
}
|
||||
|
||||
# fix the issue via repair flow
|
||||
@@ -1972,9 +1992,23 @@ async def test_migrate_chat_id(
|
||||
"action_origin": expected_action_origin,
|
||||
"chat_ids": "654321",
|
||||
"telegram_bot_entities_url": "/config/entities?domain=telegram_bot",
|
||||
"example_old": "```yaml\naction: send_message\ndata:\n target: # to be updated\n - 1234567890\n...\n```",
|
||||
"example_new_entity_id": "```yaml\naction: send_message\ndata:\n entity_id:\n - notify.telegram_bot_1234567890_1234567890 # replace with your notify entity\n...\n```",
|
||||
"example_new_chat_id": "```yaml\naction: send_message\ndata:\n chat_id:\n - 1234567890 # replace with your chat_id\n...\n```",
|
||||
"example_old": (
|
||||
"```yaml\naction: send_message\ndata:\n"
|
||||
" target: # to be updated\n"
|
||||
" - 1234567890\n...\n```"
|
||||
),
|
||||
"example_new_entity_id": (
|
||||
"```yaml\naction: send_message\ndata:\n"
|
||||
" entity_id:\n"
|
||||
" - notify.telegram_bot_1234567890_1234567890"
|
||||
" # replace with your notify entity\n...\n```"
|
||||
),
|
||||
"example_new_chat_id": (
|
||||
"```yaml\naction: send_message\ndata:\n"
|
||||
" chat_id:\n"
|
||||
" - 1234567890"
|
||||
" # replace with your chat_id\n...\n```"
|
||||
),
|
||||
},
|
||||
"last_step": None,
|
||||
"preview": None,
|
||||
|
||||
@@ -45,7 +45,8 @@ async def test_set_webhooks_failed(
|
||||
# first fail with exception, second fail with False
|
||||
assert mock_set_webhook.call_count == 2
|
||||
|
||||
# SETUP_ERROR is result of RuntimeError("Failed to register webhook with Telegram") in webhooks.py
|
||||
# SETUP_ERROR is result of RuntimeError(
|
||||
# "Failed to register webhook with Telegram") in webhooks.py
|
||||
assert mock_webhooks_config_entry.state is ConfigEntryState.SETUP_ERROR
|
||||
|
||||
# test fail after retries
|
||||
|
||||
@@ -180,7 +180,7 @@ async def test_step_import_load_json(hass: HomeAssistant, mock_tellduslive) -> N
|
||||
|
||||
@pytest.mark.parametrize("supports_local_api", [False])
|
||||
async def test_step_disco_no_local_api(hass: HomeAssistant, mock_tellduslive) -> None:
|
||||
"""Test that we trigger when configuring from discovery, not supporting local api."""
|
||||
"""Test configuring from discovery, not supporting local api."""
|
||||
flow = init_config_flow(hass)
|
||||
flow.context = {"source": SOURCE_DISCOVERY}
|
||||
|
||||
|
||||
@@ -560,7 +560,7 @@ async def test_form_user_flow_rut240(
|
||||
mock_teltasync_client: MagicMock,
|
||||
rut240_device_info: UnauthorizedStatusData,
|
||||
) -> None:
|
||||
"""RUT240 firmware omits device_identifier; the flow falls back to mnf_info.serial."""
|
||||
"""RUT240 firmware omits device_identifier; falls back to serial."""
|
||||
mock_teltasync_client.get_device_info.return_value = rut240_device_info
|
||||
mock_teltasync_client.validate_credentials.return_value = True
|
||||
|
||||
@@ -695,7 +695,7 @@ async def test_dhcp_discovery_apiv1_already_configured_aborts(
|
||||
mock_config_entry: MockConfigEntry,
|
||||
rut240_device_info: UnauthorizedStatusData,
|
||||
) -> None:
|
||||
"""An API v1.0 (e.g. RUT240) known to the device registry by MAC aborts before dhcp_confirm."""
|
||||
"""API v1.0 RUT240 known by MAC aborts before dhcp_confirm."""
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
device_registry.async_get_or_create(
|
||||
config_entry_id=mock_config_entry.entry_id,
|
||||
|
||||
@@ -156,7 +156,7 @@ async def test_temperature_trigger_sensor_behavior_any(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test temperature trigger fires for sensor entities with device_class temperature."""
|
||||
"""Test trigger fires for sensor entities with device_class temperature."""
|
||||
await assert_trigger_behavior_any(
|
||||
hass,
|
||||
target_entities=target_sensors,
|
||||
@@ -195,7 +195,7 @@ async def test_temperature_trigger_sensor_crossed_threshold_behavior_first(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test temperature crossed_threshold trigger fires on the first sensor state change."""
|
||||
"""Test crossed_threshold trigger fires on first sensor state change."""
|
||||
await assert_trigger_behavior_first(
|
||||
hass,
|
||||
target_entities=target_sensors,
|
||||
@@ -234,7 +234,7 @@ async def test_temperature_trigger_sensor_crossed_threshold_behavior_last(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test temperature crossed_threshold trigger fires when the last sensor changes state."""
|
||||
"""Test crossed_threshold trigger fires on last sensor state change."""
|
||||
await assert_trigger_behavior_last(
|
||||
hass,
|
||||
target_entities=target_sensors,
|
||||
@@ -324,7 +324,7 @@ async def test_temperature_trigger_climate_crossed_threshold_behavior_first(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test temperature crossed_threshold trigger fires on the first climate state change."""
|
||||
"""Test crossed_threshold trigger fires on first climate state change."""
|
||||
await assert_trigger_behavior_first(
|
||||
hass,
|
||||
target_entities=target_climates,
|
||||
@@ -364,7 +364,7 @@ async def test_temperature_trigger_climate_crossed_threshold_behavior_last(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test temperature crossed_threshold trigger fires when the last climate changes state."""
|
||||
"""Test crossed_threshold trigger fires on last climate state change."""
|
||||
await assert_trigger_behavior_last(
|
||||
hass,
|
||||
target_entities=target_climates,
|
||||
@@ -454,7 +454,7 @@ async def test_temperature_trigger_water_heater_crossed_threshold_behavior_first
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test temperature crossed_threshold trigger fires on the first water_heater state change."""
|
||||
"""Test crossed_threshold fires on first water_heater state change."""
|
||||
await assert_trigger_behavior_first(
|
||||
hass,
|
||||
target_entities=target_water_heaters,
|
||||
@@ -494,7 +494,7 @@ async def test_temperature_trigger_water_heater_crossed_threshold_behavior_last(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test temperature crossed_threshold trigger fires when the last water_heater changes state."""
|
||||
"""Test crossed_threshold fires on last water_heater state change."""
|
||||
await assert_trigger_behavior_last(
|
||||
hass,
|
||||
target_entities=target_water_heaters,
|
||||
@@ -587,7 +587,7 @@ async def test_temperature_trigger_weather_crossed_threshold_behavior_first(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test temperature crossed_threshold trigger fires on the first weather state change."""
|
||||
"""Test crossed_threshold trigger fires on first weather state change."""
|
||||
await assert_trigger_behavior_first(
|
||||
hass,
|
||||
target_entities=target_weathers,
|
||||
@@ -628,7 +628,7 @@ async def test_temperature_trigger_weather_crossed_threshold_behavior_last(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test temperature crossed_threshold trigger fires when the last weather changes state."""
|
||||
"""Test crossed_threshold fires on last weather state change."""
|
||||
await assert_trigger_behavior_last(
|
||||
hass,
|
||||
target_entities=target_weathers,
|
||||
@@ -648,7 +648,7 @@ async def test_temperature_trigger_weather_crossed_threshold_behavior_last(
|
||||
async def test_temperature_trigger_unit_conversion_sensor_celsius_to_fahrenheit(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test temperature trigger converts sensor value from °C to °F for threshold comparison."""
|
||||
"""Test trigger converts sensor value from C to F for comparison."""
|
||||
calls: list[str] = []
|
||||
entity_id = "sensor.test_temp"
|
||||
|
||||
@@ -706,7 +706,7 @@ async def test_temperature_trigger_unit_conversion_sensor_celsius_to_fahrenheit(
|
||||
async def test_temperature_trigger_unit_conversion_sensor_fahrenheit_to_celsius(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test temperature trigger converts sensor value from °F to °C for threshold comparison."""
|
||||
"""Test trigger converts sensor value from F to C for comparison."""
|
||||
calls: list[str] = []
|
||||
entity_id = "sensor.test_temp"
|
||||
|
||||
@@ -768,7 +768,8 @@ async def test_temperature_trigger_unit_conversion_changed(
|
||||
calls: list[str] = []
|
||||
entity_id = "sensor.test_temp"
|
||||
|
||||
# Sensor reports in °C, trigger configured in °F: above 68°F (20°C), below 77°F (25°C)
|
||||
# Sensor reports in C, trigger configured in F:
|
||||
# above 68F (20C), below 77F (25C)
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
"18",
|
||||
@@ -839,7 +840,8 @@ async def test_temperature_trigger_unit_conversion_weather(
|
||||
calls: list[str] = []
|
||||
entity_id = "weather.test"
|
||||
|
||||
# Weather reports temperature in °F, trigger configured in °C with threshold above 25°C
|
||||
# Weather reports in F, trigger configured in C with threshold
|
||||
# above 25C
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
"sunny",
|
||||
|
||||
@@ -96,7 +96,7 @@ async def async_setup_legacy_platforms(
|
||||
count: int,
|
||||
config: ConfigType | list[ConfigType],
|
||||
) -> None:
|
||||
"""Do setup of any legacy platform that supports a keyed dictionary of template entities."""
|
||||
"""Do setup of any legacy platform with keyed template entities."""
|
||||
if slug is None:
|
||||
# Lock and Weather platforms do not use a slug
|
||||
if isinstance(config, list):
|
||||
@@ -301,12 +301,13 @@ async def setup_and_test_nested_unique_id(
|
||||
entity_config: ConfigType | None,
|
||||
state_template: str | None = None,
|
||||
) -> None:
|
||||
"""Setup 2 entities with unique unique_ids in a template section that contains a unique_id.
|
||||
"""Setup 2 entities with unique_ids in a template section with a unique_id.
|
||||
|
||||
The test will verify that 2 entities are created where the unique_id appends the
|
||||
section unique_id to each entity unique_id.
|
||||
The test will verify that 2 entities are created where the unique_id
|
||||
appends the section unique_id to each entity unique_id.
|
||||
|
||||
The entity_config should not provide name or unique_id, those are added automatically.
|
||||
The entity_config should not provide name or unique_id, those are
|
||||
added automatically.
|
||||
"""
|
||||
state_config = {"state": state_template} if state_template else {}
|
||||
entities = [
|
||||
|
||||
@@ -1186,7 +1186,7 @@ async def test_trigger_with_negative_time_periods(
|
||||
async def test_trigger_template_delay_with_multiple_triggers(
|
||||
hass: HomeAssistant, delay_state: str, freezer: FrozenDateTimeFactory
|
||||
) -> None:
|
||||
"""Test trigger based binary sensor with multiple triggers occurring during the delay."""
|
||||
"""Test trigger based binary sensor with multiple triggers during delay."""
|
||||
for _ in range(10):
|
||||
# State should still be unknown
|
||||
state = hass.states.get(TEST_BINARY_SENSOR.entity_id)
|
||||
|
||||
@@ -229,7 +229,7 @@ async def test_reload_template_when_blueprint_changes(hass: HomeAssistant) -> No
|
||||
|
||||
|
||||
async def test_init_attribute_variables_from_blueprint(hass: HomeAssistant) -> None:
|
||||
"""Test a state based blueprint initializes icon, name, and picture with variables."""
|
||||
"""Test blueprint initializes icon, name, and picture with variables."""
|
||||
blueprint = "test_init_attribute_variables.yaml"
|
||||
source = "switch.foo"
|
||||
entity_id = "sensor.foo"
|
||||
|
||||
@@ -131,7 +131,8 @@ async def test_invalid_default_entity_id(
|
||||
"auto_off": "00:00:01",
|
||||
},
|
||||
},
|
||||
"The auto_off option for template binary sensor: name: Template Binary Sensor",
|
||||
"The auto_off option for template binary sensor:"
|
||||
" name: Template Binary Sensor",
|
||||
),
|
||||
(
|
||||
{
|
||||
@@ -172,7 +173,8 @@ async def test_invalid_default_entity_id(
|
||||
"auto_off": "00:00:01",
|
||||
},
|
||||
},
|
||||
"The auto_off option for template binary sensor: default_entity_id: binary_sensor.test_entity_id",
|
||||
"The auto_off option for template binary sensor:"
|
||||
" default_entity_id: binary_sensor.test_entity_id",
|
||||
),
|
||||
(
|
||||
{
|
||||
@@ -195,7 +197,8 @@ async def test_invalid_default_entity_id(
|
||||
"auto_off": "00:00:01",
|
||||
},
|
||||
},
|
||||
"The auto_off option for template binary sensor: default_entity_id: binary_sensor.test_entity_id",
|
||||
"The auto_off option for template binary sensor:"
|
||||
" default_entity_id: binary_sensor.test_entity_id",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -376,7 +379,7 @@ async def test_combined_trigger_variables(
|
||||
async def test_state_init_attribute_variables(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test a state based template entity initializes icon, name, and picture with variables."""
|
||||
"""Test state based template entity initializes attributes with variables."""
|
||||
source = "switch.foo"
|
||||
entity_id = "sensor.foo"
|
||||
|
||||
@@ -396,7 +399,9 @@ async def test_state_init_attribute_variables(
|
||||
},
|
||||
"name": "{{ state_attr(switch, 'friendly_name') }}",
|
||||
"icon": "{{ on_icon if is_state(switch, 'on') else off_icon }}",
|
||||
"picture": "{{ on_picture if is_state(switch, 'on') else off_picture }}",
|
||||
"picture": (
|
||||
"{{ on_picture if is_state(switch, 'on') else off_picture }}"
|
||||
),
|
||||
"state": "{{ is_state(switch, 'on') }}",
|
||||
},
|
||||
}
|
||||
@@ -436,7 +441,8 @@ async def test_state_init_attribute_variables(
|
||||
{
|
||||
"trigger": {"trigger": "event", "event_type": "my_event"},
|
||||
},
|
||||
"Invalid template configuration found, trigger option is missing matching domain",
|
||||
"Invalid template configuration found, trigger option is"
|
||||
" missing matching domain",
|
||||
),
|
||||
(
|
||||
{
|
||||
@@ -520,10 +526,24 @@ async def test_multiple_configuration_keys(
|
||||
"action": "cover.stop_cover",
|
||||
},
|
||||
"default_entity_id": "cover.shades_reversed",
|
||||
"icon": "{% set s = states('cover.shades_curtain') %}\n{% if s == 'open' %}\n mdi:curtains-closed\n{% else %}\n mdi:curtains\n{% endif %}",
|
||||
"icon": (
|
||||
"{% set s = states('cover.shades_curtain') %}\n"
|
||||
"{% if s == 'open' %}\n"
|
||||
" mdi:curtains-closed\n"
|
||||
"{% else %}\n"
|
||||
" mdi:curtains\n"
|
||||
"{% endif %}"
|
||||
),
|
||||
"name": "Shades Reversed",
|
||||
"unique_id": "c0223bcb-32c6-430e-a2c1-3545f8031796",
|
||||
"state": "{% set s = states('cover.shades_curtain') %}\n{% if s == 'open' %}\n closed\n{% elif s == 'closed' %}\n open\n{% elif s == 'opening' %}\n closing\n{% elif s == 'closing' %}\n opening\n{% else %}\n unknown\n{% endif %}",
|
||||
"state": (
|
||||
"{% set s = states('cover.shades_curtain') %}\n"
|
||||
"{% if s == 'open' %}\n closed\n"
|
||||
"{% elif s == 'closed' %}\n open\n"
|
||||
"{% elif s == 'opening' %}\n closing\n"
|
||||
"{% elif s == 'closing' %}\n opening\n"
|
||||
"{% else %}\n unknown\n{% endif %}"
|
||||
),
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -73,7 +73,10 @@ BINARY_SENSOR_OPTIONS = {
|
||||
(
|
||||
"binary_sensor",
|
||||
{
|
||||
"state": "{{ states('binary_sensor.one') == 'on' or states('binary_sensor.two') == 'on' }}"
|
||||
"state": (
|
||||
"{{ states('binary_sensor.one') == 'on'"
|
||||
" or states('binary_sensor.two') == 'on' }}"
|
||||
)
|
||||
},
|
||||
"on",
|
||||
{"one": "on", "two": "off"},
|
||||
@@ -85,7 +88,9 @@ BINARY_SENSOR_OPTIONS = {
|
||||
(
|
||||
"sensor",
|
||||
{
|
||||
"state": "{{ float(states('sensor.one')) + float(states('sensor.two')) }}"
|
||||
"state": (
|
||||
"{{ float(states('sensor.one')) + float(states('sensor.two')) }}"
|
||||
)
|
||||
},
|
||||
"50.0",
|
||||
{"one": "30.0", "two": "20.0"},
|
||||
@@ -570,10 +575,16 @@ async def test_config_flow_device(
|
||||
(
|
||||
"binary_sensor",
|
||||
{
|
||||
"state": "{{ states('binary_sensor.one') == 'on' or states('binary_sensor.two') == 'on' }}"
|
||||
"state": (
|
||||
"{{ states('binary_sensor.one') == 'on'"
|
||||
" or states('binary_sensor.two') == 'on' }}"
|
||||
)
|
||||
},
|
||||
{
|
||||
"state": "{{ states('binary_sensor.one') == 'on' and states('binary_sensor.two') == 'on' }}"
|
||||
"state": (
|
||||
"{{ states('binary_sensor.one') == 'on'"
|
||||
" and states('binary_sensor.two') == 'on' }}"
|
||||
)
|
||||
},
|
||||
["on", "off"],
|
||||
{"one": "on", "two": "off"},
|
||||
@@ -585,10 +596,14 @@ async def test_config_flow_device(
|
||||
(
|
||||
"sensor",
|
||||
{
|
||||
"state": "{{ float(states('sensor.one')) + float(states('sensor.two')) }}"
|
||||
"state": (
|
||||
"{{ float(states('sensor.one')) + float(states('sensor.two')) }}"
|
||||
)
|
||||
},
|
||||
{
|
||||
"state": "{{ float(states('sensor.one')) - float(states('sensor.two')) }}"
|
||||
"state": (
|
||||
"{{ float(states('sensor.one')) - float(states('sensor.two')) }}"
|
||||
)
|
||||
},
|
||||
["50.0", "10.0"],
|
||||
{"one": "30.0", "two": "20.0"},
|
||||
@@ -916,10 +931,16 @@ async def test_options(
|
||||
(
|
||||
"binary_sensor",
|
||||
{
|
||||
"state": "{{ states('binary_sensor.one') == 'on' or states('binary_sensor.two') == 'on' }}"
|
||||
"state": (
|
||||
"{{ states('binary_sensor.one') == 'on'"
|
||||
" or states('binary_sensor.two') == 'on' }}"
|
||||
)
|
||||
},
|
||||
{
|
||||
"state": "{{ states('binary_sensor.one') == 'on' and states('binary_sensor.two') == 'on' }}"
|
||||
"state": (
|
||||
"{{ states('binary_sensor.one') == 'on'"
|
||||
" and states('binary_sensor.two') == 'on' }}"
|
||||
)
|
||||
},
|
||||
{"one": "on", "two": "off"},
|
||||
{"device_class": "motion"},
|
||||
@@ -1026,7 +1047,10 @@ async def test_options_remove_device_class(
|
||||
[
|
||||
(
|
||||
"binary_sensor",
|
||||
"{{ states.binary_sensor.one.state == 'on' or states.binary_sensor.two.state == 'on' }}",
|
||||
(
|
||||
"{{ states.binary_sensor.one.state == 'on'"
|
||||
" or states.binary_sensor.two.state == 'on' }}"
|
||||
),
|
||||
{},
|
||||
{"one": "on", "two": "off"},
|
||||
["off", "on"],
|
||||
@@ -1225,7 +1249,9 @@ EARLY_END_ERROR = "invalid template (TemplateSyntaxError: unexpected 'end of tem
|
||||
),
|
||||
"unit_of_measurement": (
|
||||
"'None' is not a valid unit for device class 'energy'; "
|
||||
"expected one of 'cal', 'Gcal', 'GJ', 'GWh', 'J', 'kcal', 'kJ', 'kWh', 'Mcal', 'MJ', 'MWh', 'mWh', 'TWh', 'Wh'"
|
||||
"expected one of 'cal', 'Gcal', 'GJ', 'GWh', 'J',"
|
||||
" 'kcal', 'kJ', 'kWh', 'Mcal', 'MJ', 'MWh',"
|
||||
" 'mWh', 'TWh', 'Wh'"
|
||||
),
|
||||
},
|
||||
),
|
||||
@@ -1504,8 +1530,14 @@ async def test_config_flow_preview_bad_state(
|
||||
[
|
||||
(
|
||||
"binary_sensor",
|
||||
"{{ states('binary_sensor.one') == 'on' or states('binary_sensor.two') == 'on' }}",
|
||||
"{{ states('binary_sensor.one') == 'on' and states('binary_sensor.two') == 'on' }}",
|
||||
(
|
||||
"{{ states('binary_sensor.one') == 'on'"
|
||||
" or states('binary_sensor.two') == 'on' }}"
|
||||
),
|
||||
(
|
||||
"{{ states('binary_sensor.one') == 'on'"
|
||||
" and states('binary_sensor.two') == 'on' }}"
|
||||
),
|
||||
{},
|
||||
{},
|
||||
{"one": "on", "two": "off"},
|
||||
|
||||
@@ -524,22 +524,26 @@ async def test_position_out_of_bounds(hass: HomeAssistant) -> None:
|
||||
(
|
||||
ConfigurationStyle.MODERN,
|
||||
{},
|
||||
"Invalid config for 'template': must contain at least one of open_cover, set_cover_position.",
|
||||
"Invalid config for 'template': must contain at least one"
|
||||
" of open_cover, set_cover_position.",
|
||||
),
|
||||
(
|
||||
ConfigurationStyle.MODERN,
|
||||
OPEN_COVER,
|
||||
"Invalid config for 'template': some but not all values in the same group of inclusion 'open_or_close'",
|
||||
"Invalid config for 'template': some but not all values"
|
||||
" in the same group of inclusion 'open_or_close'",
|
||||
),
|
||||
(
|
||||
ConfigurationStyle.TRIGGER,
|
||||
{},
|
||||
"Invalid config for 'template': must contain at least one of open_cover, set_cover_position.",
|
||||
"Invalid config for 'template': must contain at least one"
|
||||
" of open_cover, set_cover_position.",
|
||||
),
|
||||
(
|
||||
ConfigurationStyle.TRIGGER,
|
||||
OPEN_COVER,
|
||||
"Invalid config for 'template': some but not all values in the same group of inclusion 'open_or_close'",
|
||||
"Invalid config for 'template': some but not all values"
|
||||
" in the same group of inclusion 'open_or_close'",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -740,7 +744,10 @@ async def test_set_position_optimistic(
|
||||
ConfigurationStyle.TRIGGER,
|
||||
{
|
||||
**SET_COVER_POSITION,
|
||||
"picture": "{{ 'foo.png' if is_state('sensor.test_state', 'open') else 'bar.png' }}",
|
||||
"picture": (
|
||||
"{{ 'foo.png' if is_state('sensor.test_state',"
|
||||
" 'open') else 'bar.png' }}"
|
||||
),
|
||||
},
|
||||
),
|
||||
],
|
||||
@@ -1013,7 +1020,11 @@ async def test_state_gets_lowercased(hass: HomeAssistant) -> None:
|
||||
(
|
||||
1,
|
||||
"{{ states.sensor.test_state.state }}",
|
||||
"mdi:window-shutter{{ '-open' if is_state('cover.test_template_cover', 'open') else '' }}",
|
||||
(
|
||||
"mdi:window-shutter{{ '-open'"
|
||||
" if is_state('cover.test_template_cover', 'open')"
|
||||
" else '' }}"
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
@@ -286,7 +286,7 @@ async def test_yaml_device_actions(
|
||||
entity_registry: er.EntityRegistry,
|
||||
calls: list,
|
||||
) -> None:
|
||||
"""Test device actions in platforms that support both trigger and modern configurations."""
|
||||
"""Test device actions in platforms supporting trigger and modern configs."""
|
||||
await _setup_and_test_yaml_device_action(
|
||||
hass,
|
||||
style,
|
||||
@@ -542,7 +542,7 @@ async def test_config_entry_device_actions(
|
||||
async def test_platform_not_ready(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test async_setup_template_platform raises PlatformNotReady when trigger object is None."""
|
||||
"""Test async_setup_template_platform raises PlatformNotReady."""
|
||||
with pytest.raises(PlatformNotReady):
|
||||
await async_setup_template_platform(
|
||||
hass,
|
||||
|
||||
@@ -168,7 +168,7 @@ async def test_reloadable_stops_on_invalid_config(hass: HomeAssistant) -> None:
|
||||
)
|
||||
@pytest.mark.usefixtures("start_ha")
|
||||
async def test_reloadable_handles_partial_valid_config(hass: HomeAssistant) -> None:
|
||||
"""Test we can still setup valid sensors when configuration.yaml has a broken entry."""
|
||||
"""Test we can still setup valid sensors when config has a broken entry."""
|
||||
hass.states.async_set("sensor.test_sensor", "mytest")
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get("sensor.state").state == "mytest"
|
||||
|
||||
@@ -266,7 +266,9 @@ def _verify(
|
||||
[
|
||||
(
|
||||
{
|
||||
CONF_ICON: "{% if states.number.test_state.state == '1' %}mdi:check{% endif %}",
|
||||
CONF_ICON: (
|
||||
"{% if states.number.test_state.state == '1' %}mdi:check{% endif %}"
|
||||
),
|
||||
**TEST_REQUIRED,
|
||||
},
|
||||
ATTR_ICON,
|
||||
@@ -274,7 +276,9 @@ def _verify(
|
||||
),
|
||||
(
|
||||
{
|
||||
CONF_PICTURE: "{% if states.number.test_state.state == '1' %}check.jpg{% endif %}",
|
||||
CONF_PICTURE: (
|
||||
"{% if states.number.test_state.state == '1' %}check.jpg{% endif %}"
|
||||
),
|
||||
**TEST_REQUIRED,
|
||||
},
|
||||
ATTR_ENTITY_PICTURE,
|
||||
@@ -425,7 +429,9 @@ async def test_not_optimistic(hass: HomeAssistant) -> None:
|
||||
{
|
||||
"set_value": [],
|
||||
"state": "{{ states('number.test_state') }}",
|
||||
"availability": "{{ is_state('binary_sensor.test_availability', 'on') }}",
|
||||
"availability": (
|
||||
"{{ is_state('binary_sensor.test_availability', 'on') }}"
|
||||
),
|
||||
},
|
||||
)
|
||||
],
|
||||
|
||||
@@ -239,7 +239,10 @@ def _verify(
|
||||
(
|
||||
{
|
||||
**TEST_OPTIONS,
|
||||
CONF_ICON: "{% if states.sensor.test_state.state == 'yes' %}mdi:check{% endif %}",
|
||||
CONF_ICON: (
|
||||
"{% if states.sensor.test_state.state == 'yes' %}"
|
||||
"mdi:check{% endif %}"
|
||||
),
|
||||
},
|
||||
ATTR_ICON,
|
||||
"mdi:check",
|
||||
@@ -247,7 +250,10 @@ def _verify(
|
||||
(
|
||||
{
|
||||
**TEST_OPTIONS,
|
||||
CONF_PICTURE: "{% if states.sensor.test_state.state == 'yes' %}check.jpg{% endif %}",
|
||||
CONF_PICTURE: (
|
||||
"{% if states.sensor.test_state.state == 'yes' %}"
|
||||
"check.jpg{% endif %}"
|
||||
),
|
||||
},
|
||||
ATTR_ENTITY_PICTURE,
|
||||
"check.jpg",
|
||||
@@ -441,7 +447,9 @@ async def test_not_optimistic(hass: HomeAssistant) -> None:
|
||||
"options": "{{ ['test', 'yes', 'no'] }}",
|
||||
"select_option": [],
|
||||
"state": "{{ states('sensor.test_state') }}",
|
||||
"availability": "{{ is_state('binary_sensor.test_availability', 'on') }}",
|
||||
"availability": (
|
||||
"{{ is_state('binary_sensor.test_availability', 'on') }}"
|
||||
),
|
||||
},
|
||||
)
|
||||
],
|
||||
|
||||
@@ -261,7 +261,10 @@ async def test_icon_template(
|
||||
("attribute_template", "before_update", "after_update"),
|
||||
[
|
||||
(
|
||||
"{{ '/local/sensor.png' if is_state('sensor.test_state', 'Works') else '' }}",
|
||||
(
|
||||
"{{ '/local/sensor.png'"
|
||||
" if is_state('sensor.test_state', 'Works') else '' }}"
|
||||
),
|
||||
"",
|
||||
"/local/sensor.png",
|
||||
),
|
||||
@@ -305,7 +308,10 @@ async def test_entity_picture_template(
|
||||
("attribute_template", "after_update"),
|
||||
[
|
||||
(
|
||||
"{{ 'It Works.' if is_state('sensor.test_state', 'Works') else 'test_template_sensor' }}",
|
||||
(
|
||||
"{{ 'It Works.' if is_state('sensor.test_state',"
|
||||
" 'Works') else 'test_template_sensor' }}"
|
||||
),
|
||||
"It Works.",
|
||||
),
|
||||
(
|
||||
@@ -688,10 +694,31 @@ async def test_this_variable(hass: HomeAssistant, before: str, after: str) -> No
|
||||
{
|
||||
"template": {
|
||||
"sensor": {
|
||||
"state": "{{ this.attributes.get('test', 'no-test!') }}: {{ this.entity_id }}",
|
||||
"icon": "mdi:{% if this.entity_id in states and 'friendly_name' in this.attributes %} {{this.attributes['friendly_name']}} {% else %}{{this.entity_id}}:{{this.entity_id in states}}{% endif %}",
|
||||
"name": "{% if this.entity_id in states and 'friendly_name' in this.attributes %} {{this.attributes['friendly_name']}} {% else %}{{this.entity_id}}:{{this.entity_id in states}}{% endif %}",
|
||||
"picture": "{% if this.entity_id in states and 'entity_picture' in this.attributes %} {{this.attributes['entity_picture']}} {% else %}{{this.entity_id}}:{{this.entity_id in states}}{% endif %}",
|
||||
"state": (
|
||||
"{{ this.attributes.get('test', 'no-test!') }}"
|
||||
": {{ this.entity_id }}"
|
||||
),
|
||||
"icon": (
|
||||
"mdi:{% if this.entity_id in states and"
|
||||
" 'friendly_name' in this.attributes %}"
|
||||
" {{this.attributes['friendly_name']}} "
|
||||
"{% else %}{{this.entity_id}}:"
|
||||
"{{this.entity_id in states}}{% endif %}"
|
||||
),
|
||||
"name": (
|
||||
"{% if this.entity_id in states and"
|
||||
" 'friendly_name' in this.attributes %}"
|
||||
" {{this.attributes['friendly_name']}} "
|
||||
"{% else %}{{this.entity_id}}:"
|
||||
"{{this.entity_id in states}}{% endif %}"
|
||||
),
|
||||
"picture": (
|
||||
"{% if this.entity_id in states and"
|
||||
" 'entity_picture' in this.attributes %}"
|
||||
" {{this.attributes['entity_picture']}} "
|
||||
"{% else %}{{this.entity_id}}:"
|
||||
"{{this.entity_id in states}}{% endif %}"
|
||||
),
|
||||
"attributes": {"test": "{{ this.entity_id }}"},
|
||||
},
|
||||
},
|
||||
@@ -753,10 +780,31 @@ async def test_this_variable_early_hass_not_running(
|
||||
{
|
||||
"template": {
|
||||
"sensor": {
|
||||
"state": "{{ this.attributes.get('test', 'no-test!') }}: {{ this.entity_id }}",
|
||||
"icon": "mdi:{% if this.entity_id in states and 'friendly_name' in this.attributes %} {{this.attributes['friendly_name']}} {% else %}{{this.entity_id}}:{{this.entity_id in states}}{% endif %}",
|
||||
"name": "{% if this.entity_id in states and 'friendly_name' in this.attributes %} {{this.attributes['friendly_name']}} {% else %}{{this.entity_id}}:{{this.entity_id in states}}{% endif %}",
|
||||
"picture": "{% if this.entity_id in states and 'entity_picture' in this.attributes %} {{this.attributes['entity_picture']}} {% else %}{{this.entity_id}}:{{this.entity_id in states}}{% endif %}",
|
||||
"state": (
|
||||
"{{ this.attributes.get('test', 'no-test!') }}"
|
||||
": {{ this.entity_id }}"
|
||||
),
|
||||
"icon": (
|
||||
"mdi:{% if this.entity_id in states and"
|
||||
" 'friendly_name' in this.attributes %}"
|
||||
" {{this.attributes['friendly_name']}} "
|
||||
"{% else %}{{this.entity_id}}:"
|
||||
"{{this.entity_id in states}}{% endif %}"
|
||||
),
|
||||
"name": (
|
||||
"{% if this.entity_id in states and"
|
||||
" 'friendly_name' in this.attributes %}"
|
||||
" {{this.attributes['friendly_name']}} "
|
||||
"{% else %}{{this.entity_id}}:"
|
||||
"{{this.entity_id in states}}{% endif %}"
|
||||
),
|
||||
"picture": (
|
||||
"{% if this.entity_id in states and"
|
||||
" 'entity_picture' in this.attributes %}"
|
||||
" {{this.attributes['entity_picture']}} "
|
||||
"{% else %}{{this.entity_id}}:"
|
||||
"{{this.entity_id in states}}{% endif %}"
|
||||
),
|
||||
"attributes": {"test": "{{ this.entity_id }}"},
|
||||
},
|
||||
},
|
||||
@@ -828,17 +876,33 @@ async def test_self_referencing_sensor_loop(
|
||||
[
|
||||
(
|
||||
{
|
||||
"state": "{{ ((states.sensor.test_template_sensor.state or 0) | int) + 1 }}",
|
||||
"icon": "{% if ((states.sensor.test_template_sensor.state or 0) | int) >= 1 %}mdi:greater{% else %}mdi:less{% endif %}",
|
||||
"state": (
|
||||
"{{ ((states.sensor.test_template_sensor.state or 0) | int) + 1 }}"
|
||||
),
|
||||
"icon": (
|
||||
"{% if ((states.sensor.test_template_sensor"
|
||||
".state or 0) | int) >= 1 %}mdi:greater"
|
||||
"{% else %}mdi:less{% endif %}"
|
||||
),
|
||||
},
|
||||
((ATTR_ICON, "mdi:greater"),),
|
||||
3,
|
||||
),
|
||||
(
|
||||
{
|
||||
"state": "{{ ((states.sensor.test_template_sensor.state or 0) | int) + 1 }}",
|
||||
"icon": "{% if ((states.sensor.test_template_sensor.state or 0) | int) > 3 %}mdi:greater{% else %}mdi:less{% endif %}",
|
||||
"picture": "{% if ((states.sensor.test_template_sensor.state or 0) | int) >= 1 %}bigpic{% else %}smallpic{% endif %}",
|
||||
"state": (
|
||||
"{{ ((states.sensor.test_template_sensor.state or 0) | int) + 1 }}"
|
||||
),
|
||||
"icon": (
|
||||
"{% if ((states.sensor.test_template_sensor"
|
||||
".state or 0) | int) > 3 %}mdi:greater"
|
||||
"{% else %}mdi:less{% endif %}"
|
||||
),
|
||||
"picture": (
|
||||
"{% if ((states.sensor.test_template_sensor"
|
||||
".state or 0) | int) >= 1 %}bigpic"
|
||||
"{% else %}smallpic{% endif %}"
|
||||
),
|
||||
},
|
||||
(
|
||||
(ATTR_ICON, "mdi:less"),
|
||||
@@ -850,8 +914,16 @@ async def test_self_referencing_sensor_loop(
|
||||
{
|
||||
"default_entity_id": TEST_SENSOR.entity_id,
|
||||
"state": "{{ 1 }}",
|
||||
"picture": "{{ ((states.sensor.test_template_sensor.attributes['entity_picture'] or 0) | int) + 1 }}",
|
||||
"name": "{{ ((states.sensor.test_template_sensor.attributes['friendly_name'] or 0) | int) + 1 }}",
|
||||
"picture": (
|
||||
"{{ ((states.sensor.test_template_sensor"
|
||||
".attributes['entity_picture'] or 0)"
|
||||
" | int) + 1 }}"
|
||||
),
|
||||
"name": (
|
||||
"{{ ((states.sensor.test_template_sensor"
|
||||
".attributes['friendly_name'] or 0)"
|
||||
" | int) + 1 }}"
|
||||
),
|
||||
},
|
||||
(
|
||||
(ATTR_ENTITY_PICTURE, "3"),
|
||||
@@ -893,19 +965,27 @@ async def test_self_referencing_icon_with_no_loop(
|
||||
hass.states.async_set("sensor.heartworm_avg_64", 10)
|
||||
hass.states.async_set("sensor.heartworm_avg_57", 10)
|
||||
|
||||
value_template_str = """{% if (states.sensor.heartworm_high_80.state|int >= 10) and (states.sensor.heartworm_low_57.state|int >= 10) %}
|
||||
extreme
|
||||
{% elif (states.sensor.heartworm_avg_64.state|int >= 30) %}
|
||||
high
|
||||
{% elif (states.sensor.heartworm_avg_64.state|int >= 14) %}
|
||||
moderate
|
||||
{% elif (states.sensor.heartworm_avg_64.state|int >= 5) %}
|
||||
slight
|
||||
{% elif (states.sensor.heartworm_avg_57.state|int >= 5) %}
|
||||
marginal
|
||||
{% elif (states.sensor.heartworm_avg_57.state|int < 5) %}
|
||||
none
|
||||
{% endif %}"""
|
||||
value_template_str = (
|
||||
"{% if (states.sensor.heartworm_high_80.state|int >= 10)"
|
||||
" and (states.sensor.heartworm_low_57.state|int >= 10) %}\n"
|
||||
" extreme\n"
|
||||
" {% elif (states.sensor.heartworm_avg_64.state"
|
||||
"|int >= 30) %}\n"
|
||||
" high\n"
|
||||
" {% elif (states.sensor.heartworm_avg_64.state"
|
||||
"|int >= 14) %}\n"
|
||||
" moderate\n"
|
||||
" {% elif (states.sensor.heartworm_avg_64.state"
|
||||
"|int >= 5) %}\n"
|
||||
" slight\n"
|
||||
" {% elif (states.sensor.heartworm_avg_57.state"
|
||||
"|int >= 5) %}\n"
|
||||
" marginal\n"
|
||||
" {% elif (states.sensor.heartworm_avg_57.state"
|
||||
"|int < 5) %}\n"
|
||||
" none\n"
|
||||
" {% endif %}"
|
||||
)
|
||||
|
||||
icon_template_str = """{% if is_state('sensor.heartworm_risk',"extreme") %}
|
||||
mdi:hazard-lights
|
||||
@@ -1051,7 +1131,9 @@ async def test_trigger_conditional_entity(hass: HomeAssistant) -> None:
|
||||
"condition": [
|
||||
{
|
||||
"condition": "template",
|
||||
"value_template": "{{ trigger.event.data.beer / 0 == 'narf' }}",
|
||||
"value_template": (
|
||||
"{{ trigger.event.data.beer / 0 == 'narf' }}"
|
||||
),
|
||||
}
|
||||
],
|
||||
"sensor": [
|
||||
@@ -1204,7 +1286,9 @@ async def test_trigger_attribute_order(
|
||||
"sensor": [
|
||||
{
|
||||
"name": "Test Sensor",
|
||||
"availability": "{{ trigger and trigger.event.data.beer == 2 }}",
|
||||
"availability": (
|
||||
"{{ trigger and trigger.event.data.beer == 2 }}"
|
||||
),
|
||||
"state": "{{ trigger.event.data.beer }}",
|
||||
"attributes": {
|
||||
"beer": "{{ trigger.event.data.beer }}",
|
||||
@@ -1235,13 +1319,16 @@ async def test_trigger_attribute_order(
|
||||
assert state.attributes["beer"] == 2
|
||||
assert "no_beer" not in state.attributes
|
||||
assert (
|
||||
"Error rendering attributes.no_beer template for sensor.test_sensor: UndefinedError: 'sad' is undefined"
|
||||
in caplog.text
|
||||
"Error rendering attributes.no_beer template for"
|
||||
" sensor.test_sensor: UndefinedError: 'sad' is undefined" in caplog.text
|
||||
)
|
||||
assert state.attributes["more_beer"] == 3
|
||||
assert (
|
||||
"Error rendering attributes.all_the_beer template for sensor.test_sensor: ValueError: Template error: int got invalid input 'unknown' when rendering template '{{ this.state | int + more_beer }}' but no default was specified"
|
||||
in caplog.text
|
||||
"Error rendering attributes.all_the_beer template for"
|
||||
" sensor.test_sensor: ValueError: Template error: int got"
|
||||
" invalid input 'unknown' when rendering template"
|
||||
" '{{ this.state | int + more_beer }}' but no default was"
|
||||
" specified" in caplog.text
|
||||
)
|
||||
|
||||
hass.bus.async_fire("test_event", {"beer": 2})
|
||||
@@ -1256,7 +1343,9 @@ async def test_trigger_attribute_order(
|
||||
|
||||
assert (
|
||||
caplog.text.count(
|
||||
"Error rendering attributes.no_beer template for sensor.test_sensor: UndefinedError: 'sad' is undefined"
|
||||
"Error rendering attributes.no_beer template for"
|
||||
" sensor.test_sensor: UndefinedError:"
|
||||
" 'sad' is undefined"
|
||||
)
|
||||
== 2
|
||||
)
|
||||
|
||||
@@ -264,7 +264,7 @@ async def test_coordinator_shutdown_unloads_script_and_condition(
|
||||
async def test_shutdown_stops_script_and_keeps_triggers_subscribed(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test that HA shutdown stops coordinator scripts without unsubscribing triggers."""
|
||||
"""Test HA shutdown stops coordinator scripts without unsubscribing."""
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
"template",
|
||||
|
||||
@@ -461,7 +461,10 @@ async def test_install_action(hass: HomeAssistant, calls: list[ServiceCall]) ->
|
||||
),
|
||||
(
|
||||
"icon",
|
||||
"{% if is_state('sensor.installed_update', 'on') %}mdi:something{% endif %}",
|
||||
(
|
||||
"{% if is_state('sensor.installed_update', 'on') %}"
|
||||
"mdi:something{% endif %}"
|
||||
),
|
||||
ATTR_ICON,
|
||||
"mdi:something",
|
||||
),
|
||||
@@ -701,7 +704,10 @@ async def test_update_percent_template(
|
||||
TEST_INSTALLED_TEMPLATE,
|
||||
TEST_LATEST_TEMPLATE,
|
||||
"update_percentage",
|
||||
"{% set e = 'sensor.test_update' %}{{ states(e) if e | has_value else None }}",
|
||||
(
|
||||
"{% set e = 'sensor.test_update' %}"
|
||||
"{{ states(e) if e | has_value else None }}"
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1014,7 +1014,10 @@ async def test_not_optimistic(
|
||||
"unique_id": TEST_VACUUM.entity_id,
|
||||
"start": [],
|
||||
**CLEAN_SEGMENTS_ACTION,
|
||||
"segments": "{{ [{'id': '1', 'name': 'Livingroom'}, {'id': '2', 'name': 'Kitchen'}] }}",
|
||||
"segments": (
|
||||
"{{ [{'id': '1', 'name': 'Livingroom'},"
|
||||
" {'id': '2', 'name': 'Kitchen'}] }}"
|
||||
),
|
||||
},
|
||||
)
|
||||
],
|
||||
@@ -1130,39 +1133,47 @@ async def test_get_segments(
|
||||
"unique_id": TEST_VACUUM.entity_id,
|
||||
"segments": "{{ [ {'id': '1'} ] }}",
|
||||
},
|
||||
"expected dictionary with keys id, name and optional group and string values",
|
||||
"expected dictionary with keys id, name and optional"
|
||||
" group and string values",
|
||||
),
|
||||
(
|
||||
{
|
||||
"unique_id": TEST_VACUUM.entity_id,
|
||||
"segments": "{{ [ {'name': 'kitchen'} ] }}",
|
||||
},
|
||||
"expected dictionary with keys id, name and optional group and string values",
|
||||
"expected dictionary with keys id, name and optional"
|
||||
" group and string values",
|
||||
),
|
||||
(
|
||||
{
|
||||
"unique_id": TEST_VACUUM.entity_id,
|
||||
"segments": "{{ [ {} ] }}",
|
||||
},
|
||||
"expected dictionary with keys id, name and optional group and string values",
|
||||
"expected dictionary with keys id, name and optional"
|
||||
" group and string values",
|
||||
),
|
||||
(
|
||||
{
|
||||
"unique_id": TEST_VACUUM.entity_id,
|
||||
"segments": "{{ [ {'id': '1', 'name': 'Kitchen', 'extra_key': 'value'} ] }}",
|
||||
"segments": (
|
||||
"{{ [ {'id': '1', 'name': 'Kitchen', 'extra_key': 'value'} ] }}"
|
||||
),
|
||||
},
|
||||
"expected dictionary with keys id, name and optional group and string values",
|
||||
"expected dictionary with keys id, name and optional"
|
||||
" group and string values",
|
||||
),
|
||||
(
|
||||
{"unique_id": TEST_VACUUM.entity_id, "segments": "{{ [[]] }}"},
|
||||
"expected dictionary with keys id, name and optional group and string values",
|
||||
"expected dictionary with keys id, name and optional"
|
||||
" group and string values",
|
||||
),
|
||||
(
|
||||
{
|
||||
"unique_id": TEST_VACUUM.entity_id,
|
||||
"segments": "{{ [ {'id': '1', 'name': 'Kitchen'}, [] ] }}",
|
||||
},
|
||||
"expected dictionary with keys id, name and optional group and string values",
|
||||
"expected dictionary with keys id, name and optional"
|
||||
" group and string values",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1197,7 +1208,11 @@ async def test_invalid_segments(
|
||||
"unique_id": TEST_VACUUM.entity_id,
|
||||
"start": [],
|
||||
**CLEAN_SEGMENTS_ACTION,
|
||||
"segments": "{{ [ {'id': '1', 'name': 'Kitchen'}, {'id': '2', 'name': states('sensor.test_attribute')}] }}",
|
||||
"segments": (
|
||||
"{{ [ {'id': '1', 'name': 'Kitchen'},"
|
||||
" {'id': '2', 'name':"
|
||||
" states('sensor.test_attribute')}] }}"
|
||||
),
|
||||
},
|
||||
)
|
||||
],
|
||||
|
||||
@@ -74,11 +74,13 @@ def create_test_entity(hass: HomeAssistant, config: dict) -> TemplateEntity:
|
||||
[
|
||||
(
|
||||
{"default_entity_id": "test.test"},
|
||||
"Received invalid test state: {} for entity test.test, expected one of mmmm, beer, is, good",
|
||||
"Received invalid test state: {} for entity"
|
||||
" test.test, expected one of mmmm, beer, is, good",
|
||||
),
|
||||
(
|
||||
{},
|
||||
"Received invalid state: {} for entity Test, expected one of mmmm, beer, is, good",
|
||||
"Received invalid state: {} for entity Test,"
|
||||
" expected one of mmmm, beer, is, good",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -152,11 +154,16 @@ async def test_none_on_unknown_and_unavailable(
|
||||
[
|
||||
(
|
||||
{"default_entity_id": "test.test"},
|
||||
"Received invalid test state: {} for entity test.test, expected one of mmmm, beer, is, good, 1, true, yes, on, enable, 0, false, no, off, disable",
|
||||
"Received invalid test state: {} for entity"
|
||||
" test.test, expected one of mmmm, beer, is, good,"
|
||||
" 1, true, yes, on, enable, 0, false, no, off,"
|
||||
" disable",
|
||||
),
|
||||
(
|
||||
{},
|
||||
"Received invalid state: {} for entity Test, expected one of mmmm, beer, is, good, 1, true, yes, on, enable, 0, false, no, off, disable",
|
||||
"Received invalid state: {} for entity Test,"
|
||||
" expected one of mmmm, beer, is, good, 1, true,"
|
||||
" yes, on, enable, 0, false, no, off, disable",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -210,11 +217,15 @@ async def test_enum_with_on_off(
|
||||
[
|
||||
(
|
||||
{"default_entity_id": "test.test"},
|
||||
"Received invalid test state: {} for entity test.test, expected one of mmmm, beer, is, good, 1, true, yes, on, enable",
|
||||
"Received invalid test state: {} for entity"
|
||||
" test.test, expected one of mmmm, beer, is, good,"
|
||||
" 1, true, yes, on, enable",
|
||||
),
|
||||
(
|
||||
{},
|
||||
"Received invalid state: {} for entity Test, expected one of mmmm, beer, is, good, 1, true, yes, on, enable",
|
||||
"Received invalid state: {} for entity Test,"
|
||||
" expected one of mmmm, beer, is, good, 1, true,"
|
||||
" yes, on, enable",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -267,11 +278,15 @@ async def test_enum_with_on(
|
||||
[
|
||||
(
|
||||
{"default_entity_id": "test.test"},
|
||||
"Received invalid test state: {} for entity test.test, expected one of mmmm, beer, is, good, 0, false, no, off, disable",
|
||||
"Received invalid test state: {} for entity"
|
||||
" test.test, expected one of mmmm, beer, is, good,"
|
||||
" 0, false, no, off, disable",
|
||||
),
|
||||
(
|
||||
{},
|
||||
"Received invalid state: {} for entity Test, expected one of mmmm, beer, is, good, 0, false, no, off, disable",
|
||||
"Received invalid state: {} for entity Test,"
|
||||
" expected one of mmmm, beer, is, good, 0, false,"
|
||||
" no, off, disable",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -324,11 +339,15 @@ async def test_enum_with_off(
|
||||
[
|
||||
(
|
||||
{"default_entity_id": "test.test"},
|
||||
"Received invalid test state: {} for entity test.test, expected one of 1, true, yes, on, enable, 0, false, no, off, disable",
|
||||
"Received invalid test state: {} for entity"
|
||||
" test.test, expected one of 1, true, yes, on,"
|
||||
" enable, 0, false, no, off, disable",
|
||||
),
|
||||
(
|
||||
{},
|
||||
"Received invalid state: {} for entity Test, expected one of 1, true, yes, on, enable, 0, false, no, off, disable",
|
||||
"Received invalid state: {} for entity Test,"
|
||||
" expected one of 1, true, yes, on, enable, 0,"
|
||||
" false, no, off, disable",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -372,11 +391,15 @@ async def test_boolean(
|
||||
[
|
||||
(
|
||||
{"default_entity_id": "test.test"},
|
||||
"Received invalid test state: {} for entity test.test, expected one of 1, true, yes, on, enable, 0, false, no, off, disable",
|
||||
"Received invalid test state: {} for entity"
|
||||
" test.test, expected one of 1, true, yes, on,"
|
||||
" enable, 0, false, no, off, disable",
|
||||
),
|
||||
(
|
||||
{},
|
||||
"Received invalid state: {} for entity Test, expected one of 1, true, yes, on, enable, 0, false, no, off, disable",
|
||||
"Received invalid state: {} for entity Test,"
|
||||
" expected one of 1, true, yes, on, enable, 0,"
|
||||
" false, no, off, disable",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -421,11 +444,16 @@ async def test_boolean_as_true(
|
||||
[
|
||||
(
|
||||
{"default_entity_id": "test.test"},
|
||||
"Received invalid test state: {} for entity test.test, expected one of 1, true, yes, on, enable, 0, false, no, off, disable, something_unique",
|
||||
"Received invalid test state: {} for entity"
|
||||
" test.test, expected one of 1, true, yes, on,"
|
||||
" enable, 0, false, no, off, disable,"
|
||||
" something_unique",
|
||||
),
|
||||
(
|
||||
{},
|
||||
"Received invalid state: {} for entity Test, expected one of 1, true, yes, on, enable, 0, false, no, off, disable, something_unique",
|
||||
"Received invalid state: {} for entity Test,"
|
||||
" expected one of 1, true, yes, on, enable, 0,"
|
||||
" false, no, off, disable, something_unique",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -584,11 +612,14 @@ async def test_number_as_int(
|
||||
[
|
||||
(
|
||||
{"default_entity_id": "test.test"},
|
||||
"Received invalid test state: {} for entity test.test, expected a number greater than or equal to 0.0",
|
||||
"Received invalid test state: {} for entity"
|
||||
" test.test, expected a number greater than or"
|
||||
" equal to 0.0",
|
||||
),
|
||||
(
|
||||
{},
|
||||
"Received invalid state: {} for entity Test, expected a number greater than or equal to 0.0",
|
||||
"Received invalid state: {} for entity Test,"
|
||||
" expected a number greater than or equal to 0.0",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -642,11 +673,14 @@ async def test_number_with_minimum(
|
||||
[
|
||||
(
|
||||
{"default_entity_id": "test.test"},
|
||||
"Received invalid test state: {} for entity test.test, expected a number less than or equal to 0.0",
|
||||
"Received invalid test state: {} for entity"
|
||||
" test.test, expected a number less than or equal"
|
||||
" to 0.0",
|
||||
),
|
||||
(
|
||||
{},
|
||||
"Received invalid state: {} for entity Test, expected a number less than or equal to 0.0",
|
||||
"Received invalid state: {} for entity Test,"
|
||||
" expected a number less than or equal to 0.0",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -696,11 +730,14 @@ async def test_number_with_maximum(
|
||||
[
|
||||
(
|
||||
{"default_entity_id": "test.test"},
|
||||
"Received invalid test state: {} for entity test.test, expected a number between 0.0 and 100.0",
|
||||
"Received invalid test state: {} for entity"
|
||||
" test.test, expected a number between 0.0 and"
|
||||
" 100.0",
|
||||
),
|
||||
(
|
||||
{},
|
||||
"Received invalid state: {} for entity Test, expected a number between 0.0 and 100.0",
|
||||
"Received invalid state: {} for entity Test,"
|
||||
" expected a number between 0.0 and 100.0",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -748,7 +785,8 @@ async def test_number_in_range(
|
||||
[
|
||||
(
|
||||
{"default_entity_id": "test.test"},
|
||||
"Received invalid test state: {} for entity test.test, expected a list of strings",
|
||||
"Received invalid test state: {} for entity"
|
||||
" test.test, expected a list of strings",
|
||||
),
|
||||
(
|
||||
{},
|
||||
@@ -807,7 +845,8 @@ async def test_list_of_strings_none_on_empty(
|
||||
[
|
||||
(
|
||||
{"default_entity_id": "test.test"},
|
||||
"Received invalid test state: {} for entity test.test, expected beer, is, GOOD",
|
||||
"Received invalid test state: {} for entity"
|
||||
" test.test, expected beer, is, GOOD",
|
||||
),
|
||||
(
|
||||
{},
|
||||
@@ -859,11 +898,13 @@ async def test_item_in_list(
|
||||
[
|
||||
(
|
||||
{"default_entity_id": "test.test"},
|
||||
"Received invalid test state: {} for entity test.test, expected one of beer, is, GOOD",
|
||||
"Received invalid test state: {} for entity"
|
||||
" test.test, expected one of beer, is, GOOD",
|
||||
),
|
||||
(
|
||||
{},
|
||||
"Received invalid state: {} for entity Test, expected one of beer, is, GOOD",
|
||||
"Received invalid state: {} for entity Test,"
|
||||
" expected one of beer, is, GOOD",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -147,7 +147,9 @@ async def test_template_state_exception(hass: HomeAssistant) -> None:
|
||||
(
|
||||
ConfigurationStyle.MODERN,
|
||||
{
|
||||
"apparent_temperature_template": "{{ states('sensor.apparent_temperature') }}",
|
||||
"apparent_temperature_template": (
|
||||
"{{ states('sensor.apparent_temperature') }}"
|
||||
),
|
||||
"attribution_template": "{{ states('sensor.attribution') }}",
|
||||
"cloud_coverage_template": "{{ states('sensor.cloud_coverage') }}",
|
||||
"condition_template": "{{ states('sensor.condition') }}",
|
||||
@@ -167,7 +169,9 @@ async def test_template_state_exception(hass: HomeAssistant) -> None:
|
||||
(
|
||||
ConfigurationStyle.TRIGGER,
|
||||
{
|
||||
"apparent_temperature_template": "{{ states('sensor.apparent_temperature') }}",
|
||||
"apparent_temperature_template": (
|
||||
"{{ states('sensor.apparent_temperature') }}"
|
||||
),
|
||||
"attribution_template": "{{ states('sensor.attribution') }}",
|
||||
"cloud_coverage_template": "{{ states('sensor.cloud_coverage') }}",
|
||||
"condition_template": "{{ states('sensor.condition') }}",
|
||||
@@ -264,15 +268,23 @@ async def test_template_state_text(hass: HomeAssistant) -> None:
|
||||
"config",
|
||||
[
|
||||
{
|
||||
"forecast_daily_template": "{{ state_attr('sensor.forecast', 'forecast') }}",
|
||||
"forecast_hourly_template": "{{ state_attr('sensor.forecast', 'forecast') }}",
|
||||
"forecast_twice_daily_template": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
|
||||
"forecast_daily_template": (
|
||||
"{{ state_attr('sensor.forecast', 'forecast') }}"
|
||||
),
|
||||
"forecast_hourly_template": (
|
||||
"{{ state_attr('sensor.forecast', 'forecast') }}"
|
||||
),
|
||||
"forecast_twice_daily_template": (
|
||||
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
|
||||
),
|
||||
**TEST_LEGACY_REQUIRED,
|
||||
},
|
||||
{
|
||||
"forecast_daily": "{{ state_attr('sensor.forecast', 'forecast') }}",
|
||||
"forecast_hourly": "{{ state_attr('sensor.forecast', 'forecast') }}",
|
||||
"forecast_twice_daily": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
|
||||
"forecast_twice_daily": (
|
||||
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
|
||||
),
|
||||
**TEST_MODERN_REQUIRED,
|
||||
},
|
||||
],
|
||||
@@ -365,36 +377,60 @@ async def test_forecasts(hass: HomeAssistant, snapshot: SnapshotAssertion) -> No
|
||||
(
|
||||
ConfigurationStyle.MODERN,
|
||||
{
|
||||
"forecast_daily_template": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
|
||||
"forecast_hourly_template": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
|
||||
"forecast_twice_daily_template": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
|
||||
"forecast_daily_template": (
|
||||
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
|
||||
),
|
||||
"forecast_hourly_template": (
|
||||
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
|
||||
),
|
||||
"forecast_twice_daily_template": (
|
||||
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
|
||||
),
|
||||
**TEST_LEGACY_REQUIRED,
|
||||
},
|
||||
),
|
||||
(
|
||||
ConfigurationStyle.TRIGGER,
|
||||
{
|
||||
"forecast_daily_template": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
|
||||
"forecast_hourly_template": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
|
||||
"forecast_twice_daily_template": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
|
||||
"forecast_daily_template": (
|
||||
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
|
||||
),
|
||||
"forecast_hourly_template": (
|
||||
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
|
||||
),
|
||||
"forecast_twice_daily_template": (
|
||||
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
|
||||
),
|
||||
**TEST_LEGACY_REQUIRED,
|
||||
},
|
||||
),
|
||||
(
|
||||
ConfigurationStyle.MODERN,
|
||||
{
|
||||
"forecast_daily": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
|
||||
"forecast_hourly": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
|
||||
"forecast_twice_daily": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
|
||||
"forecast_daily": (
|
||||
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
|
||||
),
|
||||
"forecast_hourly": (
|
||||
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
|
||||
),
|
||||
"forecast_twice_daily": (
|
||||
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
|
||||
),
|
||||
**TEST_MODERN_REQUIRED,
|
||||
},
|
||||
),
|
||||
(
|
||||
ConfigurationStyle.TRIGGER,
|
||||
{
|
||||
"forecast_daily": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
|
||||
"forecast_hourly": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
|
||||
"forecast_twice_daily": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
|
||||
"forecast_daily": (
|
||||
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
|
||||
),
|
||||
"forecast_hourly": (
|
||||
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
|
||||
),
|
||||
"forecast_twice_daily": (
|
||||
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
|
||||
),
|
||||
**TEST_MODERN_REQUIRED,
|
||||
},
|
||||
),
|
||||
@@ -507,36 +543,60 @@ async def test_forecasts_invalid(
|
||||
(
|
||||
ConfigurationStyle.MODERN,
|
||||
{
|
||||
"forecast_daily_template": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
|
||||
"forecast_hourly_template": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
|
||||
"forecast_twice_daily_template": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
|
||||
"forecast_daily_template": (
|
||||
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
|
||||
),
|
||||
"forecast_hourly_template": (
|
||||
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
|
||||
),
|
||||
"forecast_twice_daily_template": (
|
||||
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
|
||||
),
|
||||
**TEST_LEGACY_REQUIRED,
|
||||
},
|
||||
),
|
||||
(
|
||||
ConfigurationStyle.TRIGGER,
|
||||
{
|
||||
"forecast_daily_template": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
|
||||
"forecast_hourly_template": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
|
||||
"forecast_twice_daily_template": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
|
||||
"forecast_daily_template": (
|
||||
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
|
||||
),
|
||||
"forecast_hourly_template": (
|
||||
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
|
||||
),
|
||||
"forecast_twice_daily_template": (
|
||||
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
|
||||
),
|
||||
**TEST_LEGACY_REQUIRED,
|
||||
},
|
||||
),
|
||||
(
|
||||
ConfigurationStyle.MODERN,
|
||||
{
|
||||
"forecast_daily": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
|
||||
"forecast_hourly": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
|
||||
"forecast_twice_daily": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
|
||||
"forecast_daily": (
|
||||
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
|
||||
),
|
||||
"forecast_hourly": (
|
||||
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
|
||||
),
|
||||
"forecast_twice_daily": (
|
||||
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
|
||||
),
|
||||
**TEST_MODERN_REQUIRED,
|
||||
},
|
||||
),
|
||||
(
|
||||
ConfigurationStyle.TRIGGER,
|
||||
{
|
||||
"forecast_daily": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
|
||||
"forecast_hourly": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
|
||||
"forecast_twice_daily": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
|
||||
"forecast_daily": (
|
||||
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
|
||||
),
|
||||
"forecast_hourly": (
|
||||
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
|
||||
),
|
||||
"forecast_twice_daily": (
|
||||
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
|
||||
),
|
||||
**TEST_MODERN_REQUIRED,
|
||||
},
|
||||
),
|
||||
@@ -635,7 +695,9 @@ SAVED_EXTRA_DATA_WITH_FUTURE_KEY = {
|
||||
"weather": {
|
||||
"name": "test",
|
||||
"condition_template": "{{ trigger.event.data.condition }}",
|
||||
"temperature_template": "{{ trigger.event.data.temperature | float }}",
|
||||
"temperature_template": (
|
||||
"{{ trigger.event.data.temperature | float }}"
|
||||
),
|
||||
"temperature_unit": "°C",
|
||||
"humidity_template": "{{ trigger.event.data.humidity | float }}",
|
||||
},
|
||||
@@ -712,7 +774,9 @@ async def test_trigger_entity_restore_state(
|
||||
"action": [
|
||||
{
|
||||
"variables": {
|
||||
"my_variable": "{{ trigger.event.data.temperature + 1 }}"
|
||||
"my_variable": (
|
||||
"{{ trigger.event.data.temperature + 1 }}"
|
||||
)
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -760,7 +824,9 @@ async def test_restore_weather_save_state(
|
||||
"weather": {
|
||||
"name": "test",
|
||||
"condition_template": "{{ trigger.event.data.condition }}",
|
||||
"temperature_template": "{{ trigger.event.data.temperature | float }}",
|
||||
"temperature_template": (
|
||||
"{{ trigger.event.data.temperature | float }}"
|
||||
),
|
||||
"temperature_unit": "°C",
|
||||
"humidity_template": "{{ trigger.event.data.humidity | float }}",
|
||||
},
|
||||
@@ -853,7 +919,9 @@ async def test_trigger_entity_restore_state_fail(
|
||||
"weather": {
|
||||
"name": "test",
|
||||
"condition_template": "{{ trigger.event.data.condition }}",
|
||||
"temperature_template": "{{ trigger.event.data.temperature | float }}",
|
||||
"temperature_template": (
|
||||
"{{ trigger.event.data.temperature | float }}"
|
||||
),
|
||||
"temperature_unit": "°C",
|
||||
"humidity_template": "{{ trigger.event.data.humidity | float }}",
|
||||
},
|
||||
@@ -879,7 +947,10 @@ async def test_trigger_entity_restore_state_fail(
|
||||
[
|
||||
(
|
||||
{
|
||||
CONF_ICON: "{% if states.weather.test_state.state == 'sunny' %}mdi:check{% endif %}",
|
||||
CONF_ICON: (
|
||||
"{% if states.weather.test_state.state =="
|
||||
" 'sunny' %}mdi:check{% endif %}"
|
||||
),
|
||||
**TEST_LEGACY_REQUIRED,
|
||||
},
|
||||
ATTR_ICON,
|
||||
@@ -887,7 +958,10 @@ async def test_trigger_entity_restore_state_fail(
|
||||
),
|
||||
(
|
||||
{
|
||||
CONF_PICTURE: "{% if states.weather.test_state.state == 'sunny' %}check.jpg{% endif %}",
|
||||
CONF_PICTURE: (
|
||||
"{% if states.weather.test_state.state =="
|
||||
" 'sunny' %}check.jpg{% endif %}"
|
||||
),
|
||||
**TEST_LEGACY_REQUIRED,
|
||||
},
|
||||
ATTR_ENTITY_PICTURE,
|
||||
|
||||
@@ -446,7 +446,11 @@ async def test_climate_notemp(
|
||||
|
||||
with pytest.raises(
|
||||
ServiceValidationError,
|
||||
match="Set temperature action was used with the 'Lower/Upper target temperature' parameter but the entity does not support it",
|
||||
match=(
|
||||
"Set temperature action was used with the"
|
||||
" 'Lower/Upper target temperature' parameter but the"
|
||||
" entity does not support it"
|
||||
),
|
||||
):
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
|
||||
@@ -80,9 +80,14 @@ def mock_private_key():
|
||||
public_key = Mock()
|
||||
private_key.public_key.return_value = public_key
|
||||
public_key.public_bytes.side_effect = [
|
||||
b"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n-----END PUBLIC KEY-----",
|
||||
b"-----BEGIN PUBLIC KEY-----\n"
|
||||
b"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n"
|
||||
b"-----END PUBLIC KEY-----",
|
||||
bytes.fromhex(
|
||||
"0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
|
||||
"0404112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff1122"
|
||||
),
|
||||
]
|
||||
return private_key
|
||||
@@ -171,7 +176,12 @@ async def test_partner_login_partial_failure(
|
||||
},
|
||||
)
|
||||
|
||||
public_key = "0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
|
||||
public_key = (
|
||||
"0404112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff1122"
|
||||
)
|
||||
|
||||
mock_api_na = AsyncMock()
|
||||
mock_api_na.private_key = mock_private_key
|
||||
@@ -265,10 +275,20 @@ async def test_full_flow_with_domain_registration(
|
||||
mock_api.private_key = mock_private_key
|
||||
mock_api.get_private_key = AsyncMock()
|
||||
mock_api.partner_login = AsyncMock()
|
||||
mock_api.public_uncompressed_point = "0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
|
||||
mock_api.public_uncompressed_point = (
|
||||
"0404112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff1122"
|
||||
)
|
||||
mock_api.partner.register.return_value = {
|
||||
"response": {
|
||||
"public_key": "0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
|
||||
"public_key": (
|
||||
"0404112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff1122"
|
||||
)
|
||||
}
|
||||
}
|
||||
mock_api_class.return_value = mock_api
|
||||
@@ -278,7 +298,8 @@ async def test_full_flow_with_domain_registration(
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "domain_input"
|
||||
|
||||
# Enter domain - this should automatically register and go to registration_complete
|
||||
# Enter domain - this should automatically register and go to
|
||||
# registration_complete
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {CONF_DOMAIN: "example.com"}
|
||||
)
|
||||
@@ -351,11 +372,22 @@ async def test_domain_input_invalid_domain(
|
||||
assert result["step_id"] == "domain_input"
|
||||
assert result["errors"] == {CONF_DOMAIN: "invalid_domain"}
|
||||
|
||||
# Enter valid domain - this should automatically register and go to registration_complete
|
||||
mock_api.public_uncompressed_point = "0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
|
||||
# Enter valid domain - this should automatically register
|
||||
# and go to registration_complete
|
||||
mock_api.public_uncompressed_point = (
|
||||
"0404112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff1122"
|
||||
)
|
||||
mock_api.partner.register.return_value = {
|
||||
"response": {
|
||||
"public_key": "0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
|
||||
"public_key": (
|
||||
"0404112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff1122"
|
||||
)
|
||||
}
|
||||
}
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
@@ -483,7 +515,8 @@ async def test_domain_registration_precondition_failed(
|
||||
# Complete OAuth
|
||||
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||
|
||||
# Enter domain - this should go to domain_registration and then fail back to domain_input
|
||||
# Enter domain - this should go to domain_registration
|
||||
# and then fail back to domain_input
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {CONF_DOMAIN: "example.com"}
|
||||
)
|
||||
@@ -646,7 +679,12 @@ async def test_domain_registration_partial_failure(
|
||||
},
|
||||
)
|
||||
|
||||
public_key = "0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
|
||||
public_key = (
|
||||
"0404112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff"
|
||||
"112233445566778899aabbccddeeff1122"
|
||||
)
|
||||
|
||||
# Create two separate mocks for NA and EU
|
||||
mock_api_na = AsyncMock()
|
||||
|
||||
@@ -115,7 +115,7 @@ def get_lifetime_mock() -> Lifetime:
|
||||
|
||||
@dataclass
|
||||
class EntityAndExpectedValues:
|
||||
"""Class for keeping entity id along with expected value for first and second data updates."""
|
||||
"""Class for keeping entity id along with expected update values."""
|
||||
|
||||
entity_id: str
|
||||
first_value: Any
|
||||
@@ -142,7 +142,8 @@ async def _test_sensors(
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state, f"Unable to get state of {entity.entity_id}"
|
||||
assert state.state == entity.first_value, (
|
||||
f"First update: {entity.entity_id} is expected to have state {entity.first_value} but has {state.state}"
|
||||
f"First update: {entity.entity_id} is expected to have"
|
||||
f" state {entity.first_value} but has {state.state}"
|
||||
)
|
||||
|
||||
# Simulate second data update
|
||||
@@ -165,5 +166,6 @@ async def _test_sensors(
|
||||
for entity in entities_and_expected_values:
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state.state == entity.second_value, (
|
||||
f"Second update: {entity.entity_id} is expected to have state {entity.second_value} but has {state.state}"
|
||||
f"Second update: {entity.entity_id} is expected to have"
|
||||
f" state {entity.second_value} but has {state.state}"
|
||||
)
|
||||
|
||||
@@ -344,7 +344,7 @@ async def test_calendar_midnight_crossing_local_start(
|
||||
freezer: FrozenDateTimeFactory,
|
||||
mock_legacy: AsyncMock,
|
||||
) -> None:
|
||||
"""Test async_get_events includes overnight period when query starts at local midnight."""
|
||||
"""Test async_get_events includes overnight period at local midnight."""
|
||||
tz = dt_util.get_default_time_zone()
|
||||
freezer.move_to(datetime(2024, 1, 1, 10, 0, 0, tzinfo=tz))
|
||||
|
||||
|
||||
@@ -326,7 +326,9 @@ async def test_select_streaming(
|
||||
Signal.RIGHT_HAND_DRIVE: True,
|
||||
Signal.HVAC_LEFT_TEMPERATURE_REQUEST: 22,
|
||||
Signal.HVAC_RIGHT_TEMPERATURE_REQUEST: 21,
|
||||
Signal.CABIN_OVERHEAT_PROTECTION_MODE: "CabinOverheatProtectionModeStateOn",
|
||||
Signal.CABIN_OVERHEAT_PROTECTION_MODE: (
|
||||
"CabinOverheatProtectionModeStateOn"
|
||||
),
|
||||
Signal.CABIN_OVERHEAT_PROTECTION_TEMPERATURE_LIMIT: 35,
|
||||
},
|
||||
"createdAt": "2024-10-04T10:45:17.537Z",
|
||||
|
||||
@@ -781,7 +781,7 @@ async def test_vehicle_polling_version_update(
|
||||
mock_legacy: AsyncMock,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test vehicle sw_version is updated when polling coordinator receives new version."""
|
||||
"""Test vehicle sw_version updates when polling coordinator refreshes."""
|
||||
entry = await setup_platform(hass)
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
|
||||
@@ -812,7 +812,7 @@ async def test_energy_site_version_update(
|
||||
mock_site_info: AsyncMock,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test energy site sw_version is updated when info coordinator receives new version."""
|
||||
"""Test energy site sw_version updates when info coordinator refreshes."""
|
||||
entry = await setup_platform(hass)
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
|
||||
|
||||
@@ -239,7 +239,8 @@ async def test_export_rule_restore(
|
||||
},
|
||||
EnergyExportMode.NEVER.value,
|
||||
),
|
||||
# Path 3: In VPP, Export enabled but state shows disabled (current_option is NEVER)
|
||||
# Path 3: In VPP, Export enabled but state shows disabled
|
||||
# (current_option is NEVER)
|
||||
(
|
||||
{
|
||||
"customer_preferred_export_rule": "never",
|
||||
|
||||
@@ -389,7 +389,8 @@ async def test_service_validation_errors(
|
||||
)
|
||||
assert exc_info.value.translation_key == "set_scheduled_charging_time"
|
||||
|
||||
# Test set_scheduled_departure validation error (preconditioning_enabled=True but no departure_time)
|
||||
# Test set_scheduled_departure validation error
|
||||
# (preconditioning_enabled=True but no departure_time)
|
||||
with pytest.raises(ServiceValidationError) as exc_info:
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
@@ -402,7 +403,8 @@ async def test_service_validation_errors(
|
||||
)
|
||||
assert exc_info.value.translation_key == "set_scheduled_departure_preconditioning"
|
||||
|
||||
# Test set_scheduled_departure validation error (off_peak_charging_enabled=True but no end_off_peak_time)
|
||||
# Test set_scheduled_departure validation error
|
||||
# (off_peak_charging_enabled=True but no end_off_peak_time)
|
||||
with pytest.raises(ServiceValidationError) as exc_info:
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
|
||||
@@ -215,7 +215,7 @@ async def test_coordinator_energy_history_invalid_data(
|
||||
async def test_coordinator_energy_history_cold_start_invalid_data(
|
||||
hass: HomeAssistant, mock_energy_history, freezer: FrozenDateTimeFactory
|
||||
) -> None:
|
||||
"""Tests cold-start fallback when the very first energy history fetch has invalid data."""
|
||||
"""Tests cold-start fallback when first energy history fetch has invalid data."""
|
||||
|
||||
mock_energy_history.side_effect = lambda *a, **kw: {"response": {}}
|
||||
entry = await setup_platform(hass, [Platform.SENSOR])
|
||||
|
||||
@@ -219,7 +219,7 @@ async def test_input_text_state_trigger(
|
||||
trigger: str,
|
||||
states: list[BasicTriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test that the `text.changed` trigger fires when any input_text entity's state changes."""
|
||||
"""Test text.changed trigger fires on any input_text state change."""
|
||||
calls: list[str] = []
|
||||
other_entity_ids = set(target_input_texts["included_entities"]) - {entity_id}
|
||||
|
||||
|
||||
@@ -59,7 +59,8 @@ def create_tibber_device(
|
||||
charging_status: Charging status (for binary sensors).
|
||||
device_status: Device on/off status (for binary sensors).
|
||||
is_online: Device online status (for binary sensors).
|
||||
sensor_values: Dictionary mapping sensor IDs to their values for additional sensors.
|
||||
sensor_values: Dictionary mapping sensor IDs to their values
|
||||
for additional sensors.
|
||||
"""
|
||||
capabilities = []
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ async def test_new_data_api_sensors_with_disabled_by_default(
|
||||
setup_credentials: None,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test that sensors with entity_registry_enabled_default=False are disabled by default."""
|
||||
"""Test that sensors with entity_registry_enabled_default=False are disabled."""
|
||||
sensor_values = {
|
||||
"cellular.rssi": -75.0,
|
||||
"energyFlow.hour.battery.source.grid": 500.0,
|
||||
|
||||
@@ -941,7 +941,7 @@ async def test_state_changed_when_timer_restarted(hass: HomeAssistant) -> None:
|
||||
async def test_last_transition_after_restarted_timer_expires(
|
||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory
|
||||
) -> None:
|
||||
"""Test that last_transition changes from restarted to finished when timer expires."""
|
||||
"""Test last_transition changes from restarted to finished on expiry."""
|
||||
hass.set_state(CoreState.starting)
|
||||
|
||||
await async_setup_component(hass, DOMAIN, {DOMAIN: {"test1": {CONF_DURATION: 10}}})
|
||||
@@ -1366,7 +1366,7 @@ async def test_restore_active_resume(
|
||||
async def test_restore_active_finished_outside_grace(
|
||||
hass: HomeAssistant, last_transition: str | None
|
||||
) -> None:
|
||||
"""Test entity restore logic: timer is active, ended while Home Assistant was stopped."""
|
||||
"""Test entity restore: timer active, ended while HA was stopped."""
|
||||
events = async_capture_events(hass, EVENT_TIMER_FINISHED)
|
||||
assert not events
|
||||
utc_now = utcnow()
|
||||
|
||||
@@ -144,7 +144,7 @@ async def test_timer_trigger_behavior_any(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test that the timer trigger fires when any timer's last_transition changes to a specific value."""
|
||||
"""Test timer trigger fires on any timer last_transition change."""
|
||||
await assert_trigger_behavior_any(
|
||||
hass,
|
||||
target_entities=target_timers,
|
||||
@@ -202,7 +202,7 @@ async def test_timer_trigger_behavior_first(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test that the timer trigger fires when the first timer's last_transition changes to a specific value."""
|
||||
"""Test timer trigger fires on first timer last_transition change."""
|
||||
await assert_trigger_behavior_first(
|
||||
hass,
|
||||
target_entities=target_timers,
|
||||
@@ -260,7 +260,7 @@ async def test_timer_trigger_behavior_last(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test that the timer trigger fires when the last timer's last_transition changes to a specific value."""
|
||||
"""Test timer trigger fires on last timer last_transition change."""
|
||||
await assert_trigger_behavior_last(
|
||||
hass,
|
||||
target_entities=target_timers,
|
||||
@@ -388,7 +388,7 @@ async def test_time_remaining_trigger_paused_before_threshold(
|
||||
hass: HomeAssistant,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test time_remaining trigger does not fire when timer is paused before threshold."""
|
||||
"""Test time_remaining trigger does not fire when timer is paused."""
|
||||
now = dt_util.utcnow()
|
||||
calls: list[dict[str, Any]] = []
|
||||
|
||||
@@ -427,7 +427,7 @@ async def test_time_remaining_trigger_cancelled_before_threshold(
|
||||
hass: HomeAssistant,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test time_remaining trigger does not fire when timer is cancelled before threshold."""
|
||||
"""Test time_remaining trigger does not fire when timer is cancelled."""
|
||||
now = dt_util.utcnow()
|
||||
calls: list[dict[str, Any]] = []
|
||||
|
||||
@@ -516,7 +516,7 @@ async def test_time_remaining_trigger_short_timer(
|
||||
hass: HomeAssistant,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test time_remaining trigger does not fire when timer duration is shorter than remaining threshold."""
|
||||
"""Test time_remaining trigger skips when duration < threshold."""
|
||||
now = dt_util.utcnow()
|
||||
calls: list[dict[str, Any]] = []
|
||||
|
||||
@@ -585,7 +585,7 @@ async def test_time_remaining_trigger_already_active_past_threshold_at_attach(
|
||||
hass: HomeAssistant,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test trigger does not schedule for timers already past the fire point at attach."""
|
||||
"""Test trigger ignores timers already past the fire point at attach."""
|
||||
now = dt_util.utcnow()
|
||||
calls: list[dict[str, Any]] = []
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ async def test_midnight_turnover_before_midnight_outside_period(
|
||||
|
||||
@pytest.mark.freeze_time("2019-01-10 10:00:00-08:00")
|
||||
async def test_after_happens_tomorrow(hass: HomeAssistant) -> None:
|
||||
"""Test when both before and after are in the future, and after is later than before."""
|
||||
"""Test when before and after are in the future, after is later than before."""
|
||||
config = {
|
||||
"binary_sensor": [
|
||||
{"platform": "tod", "name": "Night", "after": "23:00", "before": "12:00"}
|
||||
@@ -760,7 +760,8 @@ async def test_dst5(
|
||||
]
|
||||
}
|
||||
# Test DST #5:
|
||||
# Test the case where the end time does not exist (roll out to the next available time)
|
||||
# Test case where end time does not exist
|
||||
# (roll out to the next available time)
|
||||
# First test before the sensor is turned on
|
||||
entity_id = "binary_sensor.day"
|
||||
freezer.move_to(test_time1)
|
||||
@@ -774,7 +775,8 @@ async def test_dst5(
|
||||
assert state.attributes["next_update"] == "2019-03-31T01:50:00+01:00"
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
# Seconds, test state when sensor is ON but end time has rolled out to next available time.
|
||||
# Second, test state when sensor is ON but end time has rolled
|
||||
# out to next available time.
|
||||
freezer.move_to(test_time2)
|
||||
async_fire_time_changed(hass, dt_util.utcnow())
|
||||
await hass.async_block_till_done()
|
||||
@@ -801,7 +803,8 @@ async def test_dst6(
|
||||
]
|
||||
}
|
||||
# Test DST #6:
|
||||
# Test the case where the end time does not exist (roll out to the next available time)
|
||||
# Test case where end time does not exist
|
||||
# (roll out to the next available time)
|
||||
# First test before the sensor is turned on
|
||||
entity_id = "binary_sensor.day"
|
||||
freezer.move_to(test_time1)
|
||||
@@ -815,7 +818,8 @@ async def test_dst6(
|
||||
assert state.attributes["next_update"] == "2019-03-31T03:00:00+02:00"
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
# Seconds, test state when sensor is ON but end time has rolled out to next available time.
|
||||
# Second, test state when sensor is ON but end time has rolled
|
||||
# out to next available time.
|
||||
freezer.move_to(test_time2)
|
||||
async_fire_time_changed(hass, dt_util.utcnow())
|
||||
await hass.async_block_till_done()
|
||||
|
||||
@@ -180,7 +180,7 @@ def parametrize_incomplete_condition_states_any(
|
||||
def parametrize_incomplete_condition_states_all(
|
||||
condition: str,
|
||||
) -> list[tuple[str, dict[str, Any], list[ConditionStateDescription]]]:
|
||||
"""Parametrize above/below threshold test cases for incomplete conditions with 'all' behavior."""
|
||||
"""Parametrize above/below threshold cases for incomplete 'all' conditions."""
|
||||
return [
|
||||
*parametrize_condition_states_all(
|
||||
condition=condition,
|
||||
|
||||
@@ -522,7 +522,7 @@ async def test_entity_rejoining_label_does_not_fire_trigger(
|
||||
entity_registry: er.EntityRegistry,
|
||||
label_registry: lr.LabelRegistry,
|
||||
) -> None:
|
||||
"""Test removing and re-adding an entity to a target does not fire stale triggers."""
|
||||
"""Test removing and re-adding entity to target does not fire stale triggers."""
|
||||
label_both = label_registry.async_get_label_by_name("label_both_lists")
|
||||
assert label_both is not None
|
||||
label_both_id = label_both.label_id
|
||||
|
||||
@@ -60,7 +60,11 @@ async def set_time_zone(hass: HomeAssistant):
|
||||
|
||||
def get_events_url(entity: str, start: str, end: str) -> str:
|
||||
"""Create a url to get events during the specified time range."""
|
||||
return f"/api/calendars/{entity}?start={urllib.parse.quote(start)}&end={urllib.parse.quote(end)}"
|
||||
return (
|
||||
f"/api/calendars/{entity}"
|
||||
f"?start={urllib.parse.quote(start)}"
|
||||
f"&end={urllib.parse.quote(end)}"
|
||||
)
|
||||
|
||||
|
||||
def get_events_response(start: dict[str, str], end: dict[str, str]) -> dict[str, Any]:
|
||||
@@ -138,7 +142,7 @@ async def test_update_entity_for_custom_project_no_due_date_on(
|
||||
hass: HomeAssistant,
|
||||
api: AsyncMock,
|
||||
) -> None:
|
||||
"""Test that a task without an explicit due date is considered to be in an on state."""
|
||||
"""Test that a task without an explicit due date is in an on state."""
|
||||
await async_update_entity(hass, "calendar.name")
|
||||
state = hass.states.get("calendar.name")
|
||||
assert state.state == "on"
|
||||
@@ -166,7 +170,7 @@ async def test_update_entity_for_calendar_with_due_date_in_the_future(
|
||||
api: AsyncMock,
|
||||
due: Due,
|
||||
) -> None:
|
||||
"""Test that a task with a due date in the future has on state and correct end_time."""
|
||||
"""Test that a task with a future due date has on state and correct end_time."""
|
||||
await async_update_entity(hass, "calendar.name")
|
||||
state = hass.states.get("calendar.name")
|
||||
assert state.state == "on"
|
||||
|
||||
@@ -20,7 +20,7 @@ from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
def patch_async_ble_device_from_address(
|
||||
return_value: BluetoothServiceInfoBleak | None = None,
|
||||
):
|
||||
"""Patch async_ble_device_from_address to return a mocked BluetoothServiceInfoBleak."""
|
||||
"""Patch async_ble_device_from_address to return a mock."""
|
||||
return patch(
|
||||
"homeassistant.components.bluetooth.async_ble_device_from_address",
|
||||
return_value=return_value,
|
||||
|
||||
@@ -30,7 +30,8 @@ def toloclient_fixture() -> Mock:
|
||||
def coordinator_toloclient() -> Mock:
|
||||
"""Patch ToloClient in async_setup_entry.
|
||||
|
||||
Throw exception to abort entry setup and prevent socket IO. Only testing config flow.
|
||||
Throw exception to abort entry setup and prevent socket IO.
|
||||
Only testing config flow.
|
||||
"""
|
||||
with patch(
|
||||
"homeassistant.components.tolo.coordinator.ToloClient", side_effect=Exception
|
||||
@@ -191,7 +192,7 @@ async def test_reconfigure_duplicate_ip(
|
||||
coordinator_toloclient: Mock,
|
||||
config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test a reconfigure flow where the user is trying to have to entries with the same IP."""
|
||||
"""Test a reconfigure flow where the user tries to duplicate an IP."""
|
||||
config_entry2 = MockConfigEntry(
|
||||
domain=DOMAIN, data={CONF_HOST: "127.0.0.6"}, unique_id="second_entry"
|
||||
)
|
||||
|
||||
@@ -24,7 +24,7 @@ CONFIG_DATA = {
|
||||
async def test_config_flow_success(
|
||||
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_touchlinesl_client: AsyncMock
|
||||
) -> None:
|
||||
"""Test the happy path where the provided username/password result in a new entry."""
|
||||
"""Test the happy path where username/password result in a new entry."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}
|
||||
)
|
||||
@@ -58,7 +58,7 @@ async def test_config_flow_failure_api_exceptions(
|
||||
mock_setup_entry: AsyncMock,
|
||||
mock_touchlinesl_client: AsyncMock,
|
||||
) -> None:
|
||||
"""Test for invalid credentials or API connection errors, and that the form can recover."""
|
||||
"""Test for invalid credentials or API errors, and form recovery."""
|
||||
mock_touchlinesl_client.user_id.side_effect = exception
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
||||
@@ -104,14 +104,18 @@ async def snapshot_platform(
|
||||
unique_device_classes = []
|
||||
for entity_entry in entity_entries:
|
||||
if entity_entry.translation_key:
|
||||
key = f"component.{DOMAIN}.entity.{entity_entry.domain}.{entity_entry.translation_key}.name"
|
||||
key = (
|
||||
f"component.{DOMAIN}.entity.{entity_entry.domain}"
|
||||
f".{entity_entry.translation_key}.name"
|
||||
)
|
||||
single_device_class_translation = False
|
||||
if key not in translations: # No name translation
|
||||
if entity_entry.original_device_class not in unique_device_classes:
|
||||
single_device_class_translation = True
|
||||
unique_device_classes.append(entity_entry.original_device_class)
|
||||
assert (key in translations) or single_device_class_translation, (
|
||||
f"No translation or non unique device_class for entity {entity_entry.unique_id}, expected {key}"
|
||||
f"No translation or non unique device_class for"
|
||||
f" entity {entity_entry.unique_id}, expected {key}"
|
||||
)
|
||||
assert entity_entry == snapshot(name=f"{entity_entry.entity_id}-entry"), (
|
||||
f"entity entry snapshot failed for {entity_entry.entity_id}"
|
||||
@@ -266,7 +270,8 @@ def _mocked_feature(
|
||||
) -> Feature:
|
||||
"""Get a mocked feature.
|
||||
|
||||
If kwargs are provided they will override the attributes for any features defined in fixtures.json
|
||||
If kwargs are provided they will override the attributes for any
|
||||
features defined in fixtures.json
|
||||
"""
|
||||
feature = MagicMock(spec=Feature, name=f"Mocked {id} feature")
|
||||
feature.id = id
|
||||
|
||||
@@ -1258,7 +1258,7 @@ async def test_manual_port_override_invalid(
|
||||
|
||||
|
||||
async def test_discovered_by_discovery_and_dhcp(hass: HomeAssistant) -> None:
|
||||
"""Test we get the form with discovery and abort for dhcp source when we get both."""
|
||||
"""Test we get the form with discovery and abort for dhcp source."""
|
||||
|
||||
with _patch_discovery(), _patch_single_discovery(), _patch_connect():
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
||||
@@ -192,8 +192,8 @@ async def test_config_entry_wrong_mac_Address(
|
||||
assert already_migrated_config_entry.state is ConfigEntryState.SETUP_RETRY
|
||||
|
||||
assert (
|
||||
"Unexpected device found at 127.0.0.1; expected aa:bb:cc:dd:ee:f0, found aa:bb:cc:dd:ee:ff"
|
||||
in caplog.text
|
||||
"Unexpected device found at 127.0.0.1; expected"
|
||||
" aa:bb:cc:dd:ee:f0, found aa:bb:cc:dd:ee:ff" in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@@ -273,8 +273,8 @@ async def test_config_entry_conn_params_invalid(
|
||||
assert mock_config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
assert (
|
||||
f"Invalid connection parameters dict for {IP_ADDRESS}: {entry_data.get(CONF_CONNECTION_PARAMETERS)}"
|
||||
in caplog.text
|
||||
f"Invalid connection parameters dict for {IP_ADDRESS}:"
|
||||
f" {entry_data.get(CONF_CONNECTION_PARAMETERS)}" in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@@ -519,8 +519,8 @@ async def test_unlink_devices(
|
||||
update_msg_fragment = "identifiers for device dummy (hs300):"
|
||||
update_msg = f"{expected_message} {update_msg_fragment}" if expected_message else ""
|
||||
|
||||
# Expected identifiers should include all other domains or all the newer non-mac device ids
|
||||
# or just the parent mac device id
|
||||
# Expected identifiers should include all other domains or all
|
||||
# the newer non-mac device ids or just the parent mac device id
|
||||
expected_identifiers = [
|
||||
(domain, device_id)
|
||||
for domain, device_id in test_identifiers
|
||||
|
||||
@@ -68,7 +68,7 @@ async def test_disconnected_device_sensor_not_registered(
|
||||
mock_omada_site_client: MagicMock,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test that if the gateway is not connected to the controller, gateway entities are not created."""
|
||||
"""Test gateway entities are not created when gateway is not connected."""
|
||||
|
||||
await _set_test_device_status(
|
||||
hass,
|
||||
|
||||
@@ -140,7 +140,7 @@ async def test_service_reconnect_failed_raises_homeassistanterror(
|
||||
mock_omada_client: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test reconnect client service raises the right kind of exception on service failure."""
|
||||
"""Test reconnect client service raises correct exception on failure."""
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
|
||||
@@ -106,8 +106,8 @@ async def test_trackable_without_details(
|
||||
await init_integration(hass, mock_config_entry)
|
||||
|
||||
assert (
|
||||
"Tracker xyz098 has no details and will be skipped. This happens for shared trackers"
|
||||
in caplog.text
|
||||
"Tracker xyz098 has no details and will be skipped."
|
||||
" This happens for shared trackers" in caplog.text
|
||||
)
|
||||
assert mock_config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
|
||||
@@ -148,7 +148,8 @@ async def test_migrate_config_entry_and_identifiers(
|
||||
name="Gateway",
|
||||
)
|
||||
|
||||
# Create bulb 1 on gateway 1 in Device Registry - this has the old identifiers format
|
||||
# Create bulb 1 on gateway 1 in Device Registry
|
||||
# this has the old identifiers format
|
||||
gateway1_bulb1 = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry1.entry_id,
|
||||
identifiers={(tradfri.DOMAIN, 65537)},
|
||||
@@ -156,13 +157,14 @@ async def test_migrate_config_entry_and_identifiers(
|
||||
)
|
||||
|
||||
# Update bulb 1 device to have both config entry IDs
|
||||
# This is to simulate existing data scenario with older version of tradfri component
|
||||
# This simulates existing data scenario with older tradfri version
|
||||
device_registry.async_update_device(
|
||||
gateway1_bulb1.id,
|
||||
add_config_entry_id=config_entry2.entry_id,
|
||||
)
|
||||
|
||||
# Create bulb 2 on gateway 1 in Device Registry - this has the new identifiers format
|
||||
# Create bulb 2 on gateway 1 in Device Registry
|
||||
# this has the new identifiers format
|
||||
gateway1_bulb2 = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry1.entry_id,
|
||||
identifiers={(tradfri.DOMAIN, f"{GATEWAY_ID1}-65538")},
|
||||
@@ -212,8 +214,9 @@ async def test_migrate_config_entry_and_identifiers(
|
||||
assert device_entries[0].identifiers == gateway1_device.identifiers
|
||||
assert device_entries[0].config_entries == gateway1_device.config_entries
|
||||
|
||||
# Validate that gateway 1 bulb 2 now only exists associated to config entry 3.
|
||||
# The device will have had its identifiers updated to the new format (for the tradfri
|
||||
# Validate that gateway 1 bulb 2 now only exists associated to
|
||||
# config entry 3. The device will have had its identifiers
|
||||
# updated to the new format (for the tradfri
|
||||
# domain) per migrate_config_entry_and_identifiers().
|
||||
# The device will have then been removed from config entry 1 (gateway1)
|
||||
# due to it not matching a device in the command store.
|
||||
@@ -230,9 +233,11 @@ async def test_migrate_config_entry_and_identifiers(
|
||||
("test_domain", "config_entry_3-device2"),
|
||||
}
|
||||
|
||||
# Validate that gateway 2 bulb 1 has been added to device registry and with correct unique identifiers
|
||||
# (This bulb device exists on gateway 2 because the command_store created above will be executed
|
||||
# for each gateway being set up.)
|
||||
# Validate that gateway 2 bulb 1 has been added to device
|
||||
# registry and with correct unique identifiers
|
||||
# (This bulb device exists on gateway 2 because the
|
||||
# command_store created above will be executed for each
|
||||
# gateway being set up.)
|
||||
device_entries = dr.async_entries_for_config_entry(
|
||||
device_registry, config_entry2.entry_id
|
||||
)
|
||||
|
||||
@@ -12,9 +12,19 @@ from homeassistant.data_entry_flow import FlowResultType
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
invalid_token_with_length_100_or_more = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEyMzQ1Njc4OTBxd2VydHl1aW9wYXNkZiIsImlhdCI6MTcxOTg4MTU4M30.E4T2S4RQfuI2ww74sUkkT-wyTGrV5_VDkgUdae5yo4E"
|
||||
invalid_token_with_length_100_or_more = (
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
|
||||
".eyJpZCI6IjEyMzQ1Njc4OTBxd2VydHl1aW9wYXNkZiIs"
|
||||
"ImlhdCI6MTcxOTg4MTU4M30"
|
||||
".E4T2S4RQfuI2ww74sUkkT-wyTGrV5_VDkgUdae5yo4E"
|
||||
)
|
||||
invalid_token_id = "1234567890qwertyuiopasdf"
|
||||
invalid_token_with_length_100_or_more_and_no_id = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJub2lkIjoiMTIzNDU2Nzg5MHF3ZXJ0eXVpb3Bhc2RmIiwiaWF0IjoxNzE5ODgxNTgzfQ.MaJLNWPGCE51Zibhbq-Yz7h3GkUxLurR2eoM2frnO6Y"
|
||||
invalid_token_with_length_100_or_more_and_no_id = (
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
|
||||
".eyJub2lkIjoiMTIzNDU2Nzg5MHF3ZXJ0eXVpb3Bhc2Rm"
|
||||
"IiwiaWF0IjoxNzE5ODgxNTgzfQ"
|
||||
".MaJLNWPGCE51Zibhbq-Yz7h3GkUxLurR2eoM2frnO6Y"
|
||||
)
|
||||
|
||||
|
||||
async def test_full_flow(
|
||||
|
||||
@@ -58,7 +58,7 @@ async def test_dynamic_new_device(
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test that new entities are added when a new device appears in coordinator data."""
|
||||
"""Test new entities are added when a new device appears in data."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
# Initially the existing device's battery sensor has a state
|
||||
|
||||
@@ -113,7 +113,7 @@ async def test_dynamic_new_device(
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test that new entities are added when a new device appears in coordinator data."""
|
||||
"""Test new entities are added when a new device appears in data."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
assert hass.states.get("switch.test_trmnl_sleep_mode") is not None
|
||||
|
||||
@@ -126,7 +126,7 @@ async def test_dynamic_new_device(
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test that new entities are added when a new device appears in coordinator data."""
|
||||
"""Test new entities are added when a new device appears in data."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
assert hass.states.get("time.test_trmnl_sleep_start_time") is not None
|
||||
|
||||
@@ -59,7 +59,7 @@ async def test_restore_state(
|
||||
async def test_tts_entity_subclass_properties(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test for errors when subclasses of the TextToSpeechEntity are missing required properties."""
|
||||
"""Test errors when TextToSpeechEntity subclasses miss required properties."""
|
||||
|
||||
class TestClass1(tts.TextToSpeechEntity):
|
||||
_attr_default_language = DEFAULT_LANG
|
||||
@@ -88,7 +88,9 @@ async def test_tts_entity_subclass_properties(
|
||||
await mock_config_entry_setup(hass, TestClass3())
|
||||
|
||||
assert (
|
||||
"TTS entities must either set the '_attr_supported_languages' attribute or override the 'supported_languages' property"
|
||||
"TTS entities must either set the"
|
||||
" '_attr_supported_languages' attribute or override"
|
||||
" the 'supported_languages' property"
|
||||
in [
|
||||
str(record.exc_info[1])
|
||||
for record in caplog.records
|
||||
@@ -103,7 +105,9 @@ async def test_tts_entity_subclass_properties(
|
||||
await mock_config_entry_setup(hass, TestClass4())
|
||||
|
||||
assert (
|
||||
"TTS entities must either set the '_attr_default_language' attribute or override the 'default_language' property"
|
||||
"TTS entities must either set the"
|
||||
" '_attr_default_language' attribute or override"
|
||||
" the 'default_language' property"
|
||||
in [
|
||||
str(record.exc_info[1])
|
||||
for record in caplog.records
|
||||
@@ -120,7 +124,9 @@ async def test_tts_entity_subclass_properties(
|
||||
await mock_config_entry_setup(hass, TestClass5())
|
||||
|
||||
assert (
|
||||
"TTS entities must either set the '_attr_supported_languages' attribute or override the 'supported_languages' property"
|
||||
"TTS entities must either set the"
|
||||
" '_attr_supported_languages' attribute or override"
|
||||
" the 'supported_languages' property"
|
||||
in [
|
||||
str(record.exc_info[1])
|
||||
for record in caplog.records
|
||||
@@ -137,7 +143,9 @@ async def test_tts_entity_subclass_properties(
|
||||
await mock_config_entry_setup(hass, TestClass6())
|
||||
|
||||
assert (
|
||||
"TTS entities must either set the '_attr_default_language' attribute or override the 'default_language' property"
|
||||
"TTS entities must either set the"
|
||||
" '_attr_default_language' attribute or override"
|
||||
" the 'default_language' property"
|
||||
in [
|
||||
str(record.exc_info[1])
|
||||
for record in caplog.records
|
||||
|
||||
@@ -175,7 +175,10 @@ async def test_service(
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
assert (
|
||||
mock_tts_cache_dir
|
||||
/ f"42f18378fd4393d18c8dd11d03fa9563c1e54491_en-us_-_{expected_url_suffix}.mp3"
|
||||
/ (
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491"
|
||||
f"_en-us_-_{expected_url_suffix}.mp3"
|
||||
)
|
||||
).is_file()
|
||||
|
||||
|
||||
@@ -301,7 +304,10 @@ async def test_service_default_special_language(
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
assert (
|
||||
mock_tts_cache_dir
|
||||
/ f"42f18378fd4393d18c8dd11d03fa9563c1e54491_en-us_-_{expected_url_suffix}.mp3"
|
||||
/ (
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491"
|
||||
f"_en-us_-_{expected_url_suffix}.mp3"
|
||||
)
|
||||
).is_file()
|
||||
|
||||
|
||||
@@ -361,7 +367,10 @@ async def test_service_language(
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
assert (
|
||||
mock_tts_cache_dir
|
||||
/ f"42f18378fd4393d18c8dd11d03fa9563c1e54491_de-de_-_{expected_url_suffix}.mp3"
|
||||
/ (
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491"
|
||||
f"_de-de_-_{expected_url_suffix}.mp3"
|
||||
)
|
||||
).is_file()
|
||||
|
||||
|
||||
@@ -2082,7 +2091,7 @@ async def test_async_internal_get_tts_audio_called(
|
||||
mock_tts_entity: MockTTSEntity,
|
||||
hass_client: ClientSessionGenerator,
|
||||
) -> None:
|
||||
"""Test that non-streaming entity has its async_internal_get_tts_audio method called."""
|
||||
"""Test non-streaming entity calls async_internal_get_tts_audio."""
|
||||
|
||||
await mock_config_entry_setup(hass, mock_tts_entity)
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class TuyaNotificationHelper:
|
||||
updated_status_properties: list[str] | None,
|
||||
dp_timestamps: dict[str, int] | None,
|
||||
) -> None:
|
||||
"""Trigger dispatcher_send for device update and wait for entity tasks to complete."""
|
||||
"""Trigger dispatcher_send for device update and wait for tasks."""
|
||||
for listener in self.manager.device_listeners:
|
||||
listener.update_device(device, updated_status_properties, dp_timestamps)
|
||||
await self.hass.async_block_till_done()
|
||||
|
||||
@@ -128,7 +128,10 @@ async def test_service(
|
||||
"master_mode": "home",
|
||||
"master_state": "alarm",
|
||||
# "Sensor Low Battery Test Sensor" in UTF-16BE
|
||||
"alarm_msg": "AFMAZQBuAHMAbwByACAATABvAHcAIABCAGEAdAB0AGUAcgB5ACAAVABlAHMAdAAgAFMAZQBuAHMAbwBy",
|
||||
"alarm_msg": (
|
||||
"AFMAZQBuAHMAbwByACAATABvAHcAIABCAGEAdAB0"
|
||||
"AGUAcgB5ACAAVABlAHMAdAAgAFMAZQBuAHMAbwBy"
|
||||
),
|
||||
},
|
||||
AlarmControlPanelState.ARMED_HOME,
|
||||
),
|
||||
|
||||
@@ -117,7 +117,7 @@ async def test_device_registry(
|
||||
entity_registry: er.EntityRegistry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Validate device registry snapshots for all devices, including unsupported ones."""
|
||||
"""Validate device registry snapshots for all devices."""
|
||||
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_devices)
|
||||
|
||||
|
||||
@@ -154,7 +154,9 @@ async def test_set_feeder_meal_plan_unsupported_device(
|
||||
mock_device.product_id = "unsupported_product"
|
||||
with pytest.raises(
|
||||
ServiceValidationError,
|
||||
match=f"Feeder with ID {mock_device.id} does not support meal plan functionality",
|
||||
match=(
|
||||
f"Feeder with ID {mock_device.id} does not support meal plan functionality"
|
||||
),
|
||||
):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
|
||||
@@ -212,7 +212,7 @@ async def test_turn_on_with_missing_effect(
|
||||
mock_twinkly_client: AsyncMock,
|
||||
data: dict[str, Any],
|
||||
) -> None:
|
||||
"""Test support of the light.turn_on service with rgbw color and missing effect support."""
|
||||
"""Test light.turn_on with rgbw color and missing effect support."""
|
||||
mock_twinkly_client.is_on.return_value = False
|
||||
mock_twinkly_client.get_firmware_version.return_value["version"] = "2.7.0"
|
||||
|
||||
|
||||
@@ -537,7 +537,7 @@ async def test_flow_integration_discovery_aborts_on_direct_connect_host(
|
||||
async def test_flow_integration_discovery_updates_existing_entry_on_rediscovery(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test that an existing entry's host is refreshed when rediscovered with the same MAC."""
|
||||
"""Test existing entry's host is refreshed when rediscovered with same MAC."""
|
||||
old_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id=format_mac(INTEGRATION_DISCOVERY_INFO["hw_addr"]),
|
||||
|
||||
@@ -448,7 +448,8 @@ async def test_wireless_client_go_wired_issue(
|
||||
) -> None:
|
||||
"""Test the solution to catch wireless device go wired UniFi issue.
|
||||
|
||||
UniFi Network has a known issue that when a wireless device goes away it sometimes gets marked as wired.
|
||||
UniFi Network has a known issue that when a wireless device goes away
|
||||
it sometimes gets marked as wired.
|
||||
"""
|
||||
client_payload.append(
|
||||
WIRELESS_CLIENT_1 | {"last_seen": dt_util.as_timestamp(dt_util.utcnow())}
|
||||
@@ -585,7 +586,7 @@ async def test_restoring_client(
|
||||
client_payload: list[dict[str, Any]],
|
||||
clients_all_payload: list[dict[str, Any]],
|
||||
) -> None:
|
||||
"""Verify clients are restored from clients_all if they ever was registered to entity registry."""
|
||||
"""Verify clients are restored from clients_all if registered to entity registry."""
|
||||
entity_registry.async_get_or_create(
|
||||
TRACKER_DOMAIN,
|
||||
DOMAIN,
|
||||
|
||||
@@ -408,7 +408,7 @@ async def test_light_onoff_mode_turn_on_off(
|
||||
async def test_light_rgb_vs_onoff_modes(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test that RGB and ONOFF modes are correctly assigned based on device capabilities."""
|
||||
"""Test RGB and ONOFF modes are assigned based on device capabilities."""
|
||||
assert len(hass.states.async_entity_ids(LIGHT_DOMAIN)) == 2
|
||||
|
||||
# Device with LED ring support should have RGB mode
|
||||
|
||||
@@ -1906,7 +1906,7 @@ async def test_device_with_no_matching_temperatures(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Verify that device temperature sensors is not created if there is no matching data."""
|
||||
"""Verify device temperature sensors are not created without matching data."""
|
||||
|
||||
assert len(hass.states.async_all()) == 6
|
||||
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 2
|
||||
|
||||
@@ -1271,7 +1271,8 @@ async def test_traffic_routes(
|
||||
{"entity_id": "switch.unifi_network_test_traffic_route"},
|
||||
blocking=True,
|
||||
)
|
||||
# Updating the value for traffic routes will make another call to retrieve the values
|
||||
# Updating the value for traffic routes will make another call
|
||||
# to retrieve the values
|
||||
assert aioclient_mock.call_count == call_count + 2
|
||||
expected_disable_call = deepcopy(traffic_route)
|
||||
expected_disable_call["enabled"] = False
|
||||
@@ -1327,7 +1328,8 @@ async def test_firewall_policies(
|
||||
{"entity_id": "switch.unifi_network_allow_internal_to_iot"},
|
||||
blocking=True,
|
||||
)
|
||||
# Updating the value for firewall policies will make another call to retrieve the values
|
||||
# Updating the value for firewall policies will make another call
|
||||
# to retrieve the values
|
||||
assert aioclient_mock.call_count == call_count + 2
|
||||
expected_disable_call = deepcopy(firewall_policy)
|
||||
expected_disable_call["enabled"] = False
|
||||
|
||||
@@ -157,7 +157,7 @@ async def test_v2_device_update_empty_location_id_ignored(
|
||||
init_integration: MockConfigEntry,
|
||||
mock_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test access.data.v2.device.update with empty location_id does not update state."""
|
||||
"""Test device.update with empty location_id does not update state."""
|
||||
handlers = _get_ws_handlers(mock_client)
|
||||
|
||||
update_msg = V2DeviceUpdate(
|
||||
|
||||
@@ -362,7 +362,7 @@ async def test_user_flow_ssl_context(
|
||||
verify_ssl: bool,
|
||||
expected_ssl_context_type: type,
|
||||
) -> None:
|
||||
"""Test that a pre-warmed no-verify SSL context is passed when verify_ssl is False."""
|
||||
"""Test no-verify SSL context is passed when verify_ssl is False."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}
|
||||
)
|
||||
@@ -803,7 +803,7 @@ async def test_discovery_ignored_entry(
|
||||
async def test_discovery_fallback_name_from_mac(
|
||||
hass: HomeAssistant, mock_client: MagicMock
|
||||
) -> None:
|
||||
"""Test discovery confirm uses MAC-based name when hostname and platform are absent."""
|
||||
"""Test discovery uses MAC-based name when hostname and platform are absent."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_INTEGRATION_DISCOVERY},
|
||||
|
||||
@@ -817,7 +817,7 @@ async def test_remote_view_doorbell_ring_by_door_name_fallback(
|
||||
init_integration: MockConfigEntry,
|
||||
mock_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test access.remote_view falls back to door_name lookup when device_id is unmapped."""
|
||||
"""Test remote_view falls back to door_name when device_id is unmapped."""
|
||||
handlers = _get_ws_handlers(mock_client)
|
||||
|
||||
remote_view_msg = RemoteView(
|
||||
@@ -838,7 +838,7 @@ async def test_remote_view_unknown_device_and_door_ignored(
|
||||
init_integration: MockConfigEntry,
|
||||
mock_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test access.remote_view is ignored when both device_id and door_name are unknown."""
|
||||
"""Test remote_view is ignored when device_id and door_name are unknown."""
|
||||
handlers = _get_ws_handlers(mock_client)
|
||||
|
||||
remote_view_msg = RemoteView(
|
||||
@@ -859,7 +859,7 @@ async def test_remote_view_device_mapping_via_device_update(
|
||||
init_integration: MockConfigEntry,
|
||||
mock_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test access.remote_view resolves device_id populated by access.data.device.update."""
|
||||
"""Test remote_view resolves device_id populated by data.device.update."""
|
||||
handlers = _get_ws_handlers(mock_client)
|
||||
|
||||
device_update_msg = DeviceUpdate(
|
||||
@@ -891,7 +891,7 @@ async def test_remote_view_device_mapping_via_v2_device_update(
|
||||
init_integration: MockConfigEntry,
|
||||
mock_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test access.remote_view resolves device_id populated by access.data.v2.device.update."""
|
||||
"""Test remote_view resolves device_id from data.v2.device.update."""
|
||||
handlers = _get_ws_handlers(mock_client)
|
||||
|
||||
v2_device_update_msg = V2DeviceUpdate(
|
||||
@@ -1164,7 +1164,7 @@ async def test_logs_add_no_device_and_no_enriched_door_id_ignored(
|
||||
init_integration: MockConfigEntry,
|
||||
mock_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test logs.add event is ignored when neither device mapping nor door_id resolves."""
|
||||
"""Test logs.add is ignored when neither device mapping nor door_id resolves."""
|
||||
handlers = _get_ws_handlers(mock_client)
|
||||
|
||||
log_msg = LogAdd(
|
||||
@@ -1228,7 +1228,7 @@ async def test_logs_add_direction(
|
||||
init_integration: MockConfigEntry,
|
||||
mock_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test direction attribute is included in access event from logs.add when present."""
|
||||
"""Test direction attribute is included in event from logs.add."""
|
||||
handlers = _get_ws_handlers(mock_client)
|
||||
await _populate_device_mapping(handlers)
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ async def test_setup_entry_ssl_context(
|
||||
verify_ssl: bool,
|
||||
expected_ssl_context_type: type,
|
||||
) -> None:
|
||||
"""Test that a pre-warmed no-verify SSL context is passed when verify_ssl is False."""
|
||||
"""Test no-verify SSL context is passed when verify_ssl is False."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
title="UniFi Access",
|
||||
|
||||
@@ -138,7 +138,7 @@ async def test_sensor_created_after_websocket_update_when_initial_fetch_fails(
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test websocket updates refine placeholder sensors after a transient startup error."""
|
||||
"""Test websocket updates refine placeholders after a transient startup error."""
|
||||
mock_client.get_door_lock_rule = AsyncMock(
|
||||
side_effect=ApiConnectionError("Connection failed")
|
||||
)
|
||||
|
||||
@@ -470,7 +470,7 @@ def mock_ufp_reauth_entry():
|
||||
|
||||
@pytest.fixture(name="ufp_reauth_entry_alt")
|
||||
def mock_ufp_reauth_entry_alt():
|
||||
"""Mock the unifiprotect config entry with alternate port/SSL for reauth/reconfigure tests."""
|
||||
"""Mock the unifiprotect config entry with alt port/SSL for reauth tests."""
|
||||
return MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
|
||||
@@ -727,10 +727,11 @@ async def test_aiport_no_binary_sensor_entities(
|
||||
ufp: MockUFPFixture,
|
||||
aiport: AiPort,
|
||||
) -> None:
|
||||
"""Test that AI Port devices do not create camera-specific binary sensor entities."""
|
||||
"""Test AI Port devices do not create camera-specific binary sensors."""
|
||||
await init_entry(hass, ufp, [aiport])
|
||||
|
||||
# AI Port should not create any camera-specific binary sensors (motion, smart detection, etc.)
|
||||
# AI Port should not create any camera-specific binary sensors
|
||||
# (motion, smart detection, etc.)
|
||||
# NVR HDD sensors will still be created, but no AI Port-specific entities
|
||||
entity_registry = er.async_get(hass)
|
||||
entities = er.async_entries_for_config_entry(entity_registry, ufp.entry.entry_id)
|
||||
|
||||
@@ -166,7 +166,10 @@ def validate_rtsp_camera_entity(
|
||||
|
||||
entity_name = f"{camera_obj.name} {channel.name} Resolution Channel (Insecure)"
|
||||
unique_id = f"{camera_obj.mac}_{channel.id}_insecure"
|
||||
entity_id = f"camera.{entity_name.replace(' ', '_').replace('(', '').replace(')', '').lower()}"
|
||||
entity_id = (
|
||||
"camera."
|
||||
f"{entity_name.replace(' ', '_').replace('(', '').replace(')', '').lower()}"
|
||||
)
|
||||
|
||||
entity_registry = er.async_get(hass)
|
||||
entity = entity_registry.async_get(entity_id)
|
||||
|
||||
@@ -676,10 +676,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_updated(
|
||||
assert mock_config.data[CONF_HOST] == DIRECT_CONNECT_DOMAIN
|
||||
|
||||
|
||||
async def test_discovered_by_unifi_discovery_direct_connect_updated_but_not_using_direct_connect(
|
||||
async def test_discovered_by_unifi_discovery_dc_updated_but_not_using_dc(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test a discovery from unifi-discovery updates the host but not direct connect if its not in use."""
|
||||
"""Test discovery updates the host but not direct connect if not in use."""
|
||||
mock_config = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
@@ -713,10 +713,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_updated_but_not_usin
|
||||
assert mock_config.data[CONF_HOST] == "127.0.0.1"
|
||||
|
||||
|
||||
async def test_discovered_by_unifi_discovery_does_not_update_ip_when_console_is_still_online(
|
||||
async def test_discovered_by_unifi_discovery_no_update_ip_when_console_online(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test a discovery from unifi-discovery does not update the ip unless the console at the old ip is offline."""
|
||||
"""Test discovery does not update IP unless old console is offline."""
|
||||
mock_config = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
@@ -948,10 +948,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_on_different_interfa
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_discovered_by_unifi_discovery_direct_connect_on_different_interface_ip_matches(
|
||||
async def test_discovered_by_unifi_discovery_dc_different_interface_ip_matches(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test a discovery from unifi-discovery from an alternate interface when the ip matches."""
|
||||
"""Test discovery from alternate interface when the IP matches."""
|
||||
mock_config = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
@@ -978,10 +978,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_on_different_interfa
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_discovered_by_unifi_discovery_direct_connect_on_different_interface_resolver(
|
||||
async def test_discovered_by_unifi_discovery_dc_different_interface_resolver(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test a discovery from unifi-discovery from an alternate interface when direct connect domain resolves to host ip."""
|
||||
"""Test discovery from alternate interface when direct connect resolves."""
|
||||
mock_config = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
@@ -1019,10 +1019,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_on_different_interfa
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_discovered_by_unifi_discovery_direct_connect_on_different_interface_resolver_fails(
|
||||
async def test_discovered_by_unifi_discovery_dc_different_interface_resolver_fails(
|
||||
hass: HomeAssistant, bootstrap: Bootstrap, nvr: NVR
|
||||
) -> None:
|
||||
"""Test we can still configure if the resolver fails."""
|
||||
"""Test we can still configure when the resolver fails."""
|
||||
mock_config = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
@@ -1110,10 +1110,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_on_different_interfa
|
||||
assert len(mock_setup.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_discovered_by_unifi_discovery_direct_connect_on_different_interface_resolver_no_result(
|
||||
async def test_discovered_by_unifi_discovery_dc_different_interface_resolver_no_result(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test a discovery from unifi-discovery from an alternate interface when direct connect domain resolve has no result."""
|
||||
"""Test discovery from alternate interface when resolve has no result."""
|
||||
mock_config = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
|
||||
@@ -964,7 +964,8 @@ async def test_vehicle_detection_multiple_thumbnails(
|
||||
|
||||
unsub = async_track_state_change_event(hass, entity_id, _capture_event)
|
||||
|
||||
# Create event with multiple vehicle thumbnails - best should be highest confidence LPR
|
||||
# Create event with multiple vehicle thumbnails
|
||||
# best should be highest confidence LPR
|
||||
event = Event(
|
||||
model=ModelType.EVENT,
|
||||
id="test_multi_thumbnail_id",
|
||||
@@ -1605,5 +1606,6 @@ async def test_aiport_no_event_entities(
|
||||
"""Test that AI Port devices do not create camera-specific event entities."""
|
||||
await init_entry(hass, ufp, [aiport])
|
||||
|
||||
# AI Port should not create any camera-specific event entities (doorbell, motion, etc.)
|
||||
# AI Port should not create any camera-specific event entities
|
||||
# (doorbell, motion, etc.)
|
||||
assert_entity_counts(hass, Platform.EVENT, 0, 0)
|
||||
|
||||
@@ -308,7 +308,7 @@ async def test_setup_failed_error(hass: HomeAssistant, ufp: MockUFPFixture) -> N
|
||||
|
||||
|
||||
async def test_setup_failed_auth(hass: HomeAssistant, ufp: MockUFPFixture) -> None:
|
||||
"""Test setup of unifiprotect entry with unauthorized error after multiple retries."""
|
||||
"""Test setup of unifiprotect entry with unauthorized error after retries."""
|
||||
|
||||
ufp.api.update = AsyncMock(side_effect=NotAuthorized)
|
||||
|
||||
@@ -437,7 +437,7 @@ async def test_async_ufp_instance_for_config_entry_ids(
|
||||
mock_entries: list[MockConfigEntry],
|
||||
expected_result: str | None,
|
||||
) -> None:
|
||||
"""Test async_ufp_instance_for_config_entry_ids with various entry configurations."""
|
||||
"""Test async_ufp_instance_for_config_entry_ids with various configs."""
|
||||
|
||||
for index, entry in enumerate(mock_entries):
|
||||
entry.add_to_hass(hass)
|
||||
@@ -523,7 +523,8 @@ async def test_setup_handles_api_key_creation_bad_request(
|
||||
hass: HomeAssistant, ufp: MockUFPFixture, mock_user_can_write_nvr: Mock
|
||||
) -> None:
|
||||
"""Test handling of API key creation BadRequest error."""
|
||||
# Setup: API key is not set, user has write permissions, but creation fails with BadRequest
|
||||
# Setup: API key is not set, user has write permissions,
|
||||
# but creation fails with BadRequest
|
||||
ufp.api.is_api_key_set.return_value = False
|
||||
ufp.api.create_api_key = AsyncMock(
|
||||
side_effect=BadRequest("Invalid API key creation request")
|
||||
|
||||
@@ -655,8 +655,8 @@ async def test_browse_media_recent_truncated(
|
||||
browse = await source.async_browse_media(media_item)
|
||||
|
||||
assert (
|
||||
browse.title
|
||||
== f"UnifiProtect > {doorbell.name} > Motion Events > Last 24 Hours (1 TRUNCATED)"
|
||||
browse.title == f"UnifiProtect > {doorbell.name} > Motion Events"
|
||||
" > Last 24 Hours (1 TRUNCATED)"
|
||||
)
|
||||
assert browse.identifier == base_id
|
||||
assert len(browse.children) == 1
|
||||
@@ -898,7 +898,10 @@ async def test_browse_media_browse_day(
|
||||
event._api = ufp.api
|
||||
ufp.api.get_events_raw = AsyncMock(return_value=[event.unifi_dict()])
|
||||
|
||||
base_id = f"test_id:browse:{doorbell.id}:motion:range:{fixed_now.year}:{fixed_now.month}:1"
|
||||
base_id = (
|
||||
f"test_id:browse:{doorbell.id}:motion:range"
|
||||
f":{fixed_now.year}:{fixed_now.month}:1"
|
||||
)
|
||||
source = await async_get_media_source(hass)
|
||||
media_item = MediaSourceItem(hass, DOMAIN, base_id, None)
|
||||
|
||||
@@ -906,8 +909,8 @@ async def test_browse_media_browse_day(
|
||||
|
||||
start = fixed_now.replace(day=1)
|
||||
assert (
|
||||
browse.title
|
||||
== f"UnifiProtect > {doorbell.name} > Motion Events > {fixed_now.strftime('%B %Y')} > {start.strftime('%x')} (1)"
|
||||
browse.title == f"UnifiProtect > {doorbell.name} > Motion Events"
|
||||
f" > {fixed_now.strftime('%B %Y')} > {start.strftime('%x')} (1)"
|
||||
)
|
||||
assert browse.identifier == base_id
|
||||
assert len(browse.children) == 1
|
||||
@@ -949,8 +952,8 @@ async def test_browse_media_browse_whole_month(
|
||||
browse = await source.async_browse_media(media_item)
|
||||
|
||||
assert (
|
||||
browse.title
|
||||
== f"UnifiProtect > {doorbell.name} > All Events > {fixed_now.strftime('%B %Y')} > Whole Month (1)"
|
||||
browse.title == f"UnifiProtect > {doorbell.name} > All Events"
|
||||
f" > {fixed_now.strftime('%B %Y')} > Whole Month (1)"
|
||||
)
|
||||
assert browse.identifier == base_id
|
||||
assert len(browse.children) == 1
|
||||
@@ -1036,8 +1039,8 @@ async def test_browse_media_browse_whole_month_december(
|
||||
browse = await source.async_browse_media(media_item)
|
||||
|
||||
assert (
|
||||
browse.title
|
||||
== f"UnifiProtect > {doorbell.name} > All Events > {fixed_now.strftime('%B %Y')} > Whole Month (1)"
|
||||
browse.title == f"UnifiProtect > {doorbell.name} > All Events"
|
||||
f" > {fixed_now.strftime('%B %Y')} > Whole Month (1)"
|
||||
)
|
||||
assert browse.identifier == base_id
|
||||
assert len(browse.children) == 1
|
||||
|
||||
@@ -447,7 +447,7 @@ async def test_relay_switch_command_when_output_gone(
|
||||
hass: HomeAssistant,
|
||||
ufp_with_relay: tuple[MockUFPFixture, Mock],
|
||||
) -> None:
|
||||
"""Command raises HomeAssistantError when the relay output channel is no longer present."""
|
||||
"""Command raises HomeAssistantError when relay output channel is gone."""
|
||||
ufp, relay = ufp_with_relay
|
||||
await init_entry(hass, ufp, [])
|
||||
|
||||
|
||||
@@ -525,7 +525,7 @@ async def test_ptz_goto_home_preset_client_error(
|
||||
ufp: MockUFPFixture,
|
||||
ptz_camera: Camera,
|
||||
) -> None:
|
||||
"""Test ptz_goto_preset service with home preset when ptz_goto_preset_public raises ClientError."""
|
||||
"""Test ptz_goto_preset with home preset when it raises ClientError."""
|
||||
ptz_camera.get_ptz_patrols.return_value = []
|
||||
await init_entry(hass, ufp, [ptz_camera])
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ async def test_siren_turn_on_with_duration(
|
||||
seconds: int,
|
||||
expected: SirenDuration,
|
||||
) -> None:
|
||||
"""Passing a valid duration to turn_on calls play with the matching SirenDuration."""
|
||||
"""Valid duration to turn_on calls play with matching SirenDuration."""
|
||||
await init_entry(hass, ufp_with_siren, [])
|
||||
|
||||
await hass.services.async_call(
|
||||
@@ -603,7 +603,7 @@ async def test_siren_auto_off_timer_scheduled_at_startup(
|
||||
ufp_with_siren: MockUFPFixture,
|
||||
siren: Mock,
|
||||
) -> None:
|
||||
"""Auto-off timer is scheduled during async_added_to_hass for an already-active siren.
|
||||
"""Auto-off timer is scheduled for an already-active siren.
|
||||
|
||||
If a timed run is already in progress when HA starts, the entity must
|
||||
schedule its own auto-off callback immediately (not wait for a WS update)
|
||||
|
||||
@@ -126,7 +126,7 @@ async def ids_from_device_description(
|
||||
device: ProtectAdoptableDeviceModel,
|
||||
description: EntityDescription,
|
||||
) -> tuple[str, str]:
|
||||
"""Return expected unique_id and entity_id using real Home Assistant translation logic."""
|
||||
"""Return expected unique_id and entity_id using HA translation logic."""
|
||||
|
||||
entity_name = normalize_name(device.display_name)
|
||||
|
||||
|
||||
@@ -58,7 +58,8 @@ async def test_login_error(
|
||||
ANY,
|
||||
exc=UpCloudAPIError(
|
||||
error_code="AUTHENTICATION_FAILED",
|
||||
error_message="Authentication failed using the given username and password.",
|
||||
error_message="Authentication failed using the given"
|
||||
" username and password.",
|
||||
),
|
||||
)
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
||||
@@ -323,7 +323,8 @@ async def test_entity_with_auto_update(
|
||||
# Should not be able to clear a skipped the update
|
||||
with pytest.raises(
|
||||
HomeAssistantError,
|
||||
match="Clearing skipped update is not supported for update.update_with_auto_update",
|
||||
match="Clearing skipped update is not supported"
|
||||
" for update.update_with_auto_update",
|
||||
):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
|
||||
@@ -89,7 +89,7 @@ async def test_update_state_trigger_behavior_any(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test that the update state trigger fires when any update state changes to a specific state."""
|
||||
"""Test update state trigger fires when any update changes to a specific state."""
|
||||
await assert_trigger_behavior_any(
|
||||
hass,
|
||||
target_entities=target_updates,
|
||||
@@ -127,7 +127,7 @@ async def test_update_state_trigger_behavior_first(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test that the update state trigger fires when the first update changes to a specific state."""
|
||||
"""Test update state trigger fires when first update changes to a specific state."""
|
||||
await assert_trigger_behavior_first(
|
||||
hass,
|
||||
target_entities=target_updates,
|
||||
@@ -165,7 +165,7 @@ async def test_update_state_trigger_behavior_last(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test that the update state trigger fires when the last update changes to a specific state."""
|
||||
"""Test update state trigger fires when last update changes to a specific state."""
|
||||
await assert_trigger_behavior_last(
|
||||
hass,
|
||||
target_entities=target_updates,
|
||||
|
||||
@@ -141,7 +141,7 @@ async def test_flow_ssdp_non_igd_device(hass: HomeAssistant) -> None:
|
||||
ssdp_location=TEST_LOCATION,
|
||||
ssdp_all_locations=[TEST_LOCATION],
|
||||
upnp={
|
||||
ATTR_UPNP_DEVICE_TYPE: "urn:schemas-upnp-org:device:WFADevice:1", # Non-IGD
|
||||
ATTR_UPNP_DEVICE_TYPE: "urn:schemas-upnp-org:device:WFADevice:1",
|
||||
},
|
||||
),
|
||||
)
|
||||
@@ -184,7 +184,7 @@ async def test_flow_ssdp_no_mac_address(hass: HomeAssistant) -> None:
|
||||
|
||||
@pytest.mark.usefixtures("mock_mac_address_from_host")
|
||||
async def test_flow_ssdp_discovery_changed_udn_match_mac(hass: HomeAssistant) -> None:
|
||||
"""Test config flow: discovery through ssdp, same device, but new UDN, matched on mac address."""
|
||||
"""Test config flow: ssdp discovery, same device, new UDN, matched on MAC."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id=TEST_USN,
|
||||
@@ -216,7 +216,7 @@ async def test_flow_ssdp_discovery_changed_udn_match_mac(hass: HomeAssistant) ->
|
||||
|
||||
@pytest.mark.usefixtures("mock_mac_address_from_host")
|
||||
async def test_flow_ssdp_discovery_changed_udn_match_host(hass: HomeAssistant) -> None:
|
||||
"""Test config flow: discovery through ssdp, same device, but new UDN, matched on mac address."""
|
||||
"""Test config flow: ssdp discovery, same device, new UDN, matched on host."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id=TEST_USN,
|
||||
@@ -253,7 +253,7 @@ async def test_flow_ssdp_discovery_changed_udn_match_host(hass: HomeAssistant) -
|
||||
async def test_flow_ssdp_discovery_changed_udn_but_st_differs(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test config flow: discovery through ssdp, same device, but new UDN, and different ST, so not matched --> new discovery."""
|
||||
"""Test config flow: ssdp discovery, same device, new UDN, different ST."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id=TEST_USN,
|
||||
@@ -342,7 +342,7 @@ async def test_flow_ssdp_discovery_changed_location(hass: HomeAssistant) -> None
|
||||
|
||||
@pytest.mark.usefixtures("mock_mac_address_from_host")
|
||||
async def test_flow_ssdp_discovery_ignored_entry(hass: HomeAssistant) -> None:
|
||||
"""Test config flow: discovery through ssdp, same device, but new UDN, matched on mac address."""
|
||||
"""Test config flow: ssdp, same device, new UDN, matched on MAC."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id=TEST_USN,
|
||||
@@ -370,7 +370,7 @@ async def test_flow_ssdp_discovery_ignored_entry(hass: HomeAssistant) -> None:
|
||||
async def test_flow_ssdp_discovery_changed_udn_ignored_entry(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test config flow: discovery through ssdp, same device, but new UDN, matched on mac address, entry ignored."""
|
||||
"""Test config flow: ssdp, same device, new UDN, matched on MAC, ignored."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id=TEST_USN,
|
||||
@@ -450,7 +450,7 @@ async def test_flow_user_no_discovery(hass: HomeAssistant) -> None:
|
||||
"mock_mac_address_from_host",
|
||||
)
|
||||
async def test_flow_ssdp_with_mismatched_udn(hass: HomeAssistant) -> None:
|
||||
"""Test config flow: discovered + configured through ssdp, where the UDN differs in the SSDP-discovery vs device description."""
|
||||
"""Test config flow: UDN differs in SSDP-discovery vs device description."""
|
||||
# Discovered via step ssdp.
|
||||
test_discovery = copy.deepcopy(TEST_DISCOVERY)
|
||||
test_discovery.upnp[ATTR_UPNP_UDN] = "uuid:another_udn"
|
||||
|
||||
@@ -122,7 +122,7 @@ async def test_async_setup_entry_multi_location(
|
||||
async def test_async_setup_udn_mismatch(
|
||||
hass: HomeAssistant, mock_async_create_device: AsyncMock
|
||||
) -> None:
|
||||
"""Test async_setup_entry for a device which reports a different UDN from SSDP-discovery and device description."""
|
||||
"""Test async_setup_entry for a device with different UDN from SSDP."""
|
||||
test_discovery = copy.deepcopy(TEST_DISCOVERY)
|
||||
test_discovery.upnp[ATTR_UPNP_UDN] = "uuid:another_udn"
|
||||
|
||||
@@ -236,7 +236,8 @@ async def test_async_setup_entry_force_poll_subscribe_error(
|
||||
mock_igd_device.async_subscribe_services.side_effect = UpnpCommunicationError
|
||||
mock_igd_device.async_unsubscribe_services.side_effect = UpnpCommunicationError
|
||||
|
||||
# Load config_entry, should still be able to load, falling back to polling/the old functionality.
|
||||
# Load config_entry, should still be able to load,
|
||||
# falling back to polling/the old functionality.
|
||||
entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id) is True
|
||||
|
||||
|
||||
@@ -462,7 +462,7 @@ async def test_hassio_addon_discovery_ignored(
|
||||
async def test_hassio_addon_discovery_update_info(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test we abort discovery flow if already configured and we update from discovery info."""
|
||||
"""Test we abort discovery flow if already configured and update info."""
|
||||
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
|
||||
@@ -55,8 +55,8 @@ async def test_reauthentication_trigger_in_setup(
|
||||
assert flow["context"]["entry_id"] == mock_config_entry.entry_id
|
||||
|
||||
assert (
|
||||
"Config entry 'test@test.test' for uptimerobot integration could not authenticate"
|
||||
in caplog.text
|
||||
"Config entry 'test@test.test' for uptimerobot integration"
|
||||
" could not authenticate" in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@@ -88,8 +88,8 @@ async def test_reauthentication_trigger_key_read_only(
|
||||
assert flow["context"]["entry_id"] == mock_config_entry.entry_id
|
||||
|
||||
assert (
|
||||
"Config entry 'test@test.test' for uptimerobot integration could not authenticate"
|
||||
in caplog.text
|
||||
"Config entry 'test@test.test' for uptimerobot integration"
|
||||
" could not authenticate" in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ async def test_device_management(
|
||||
device_registry: dr.DeviceRegistry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test that we are adding and removing devices for monitors returned from the API."""
|
||||
"""Test adding and removing devices for monitors returned from the API."""
|
||||
mock_entry = await setup_uptimerobot_integration(hass)
|
||||
|
||||
devices = dr.async_entries_for_config_entry(device_registry, mock_entry.entry_id)
|
||||
|
||||
@@ -253,7 +253,7 @@ async def test_discovered_by_websocket_scan(
|
||||
async def test_discovered_by_websocket_scan_limited_by_description_matcher(
|
||||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
||||
) -> None:
|
||||
"""Test a device is discovered from websocket scan is limited by the description matcher."""
|
||||
"""Test websocket scan discovery is limited by the description matcher."""
|
||||
new_usb = [
|
||||
{"domain": "test1", "vid": "3039", "pid": "3039", "description": "*2652*"}
|
||||
]
|
||||
@@ -380,7 +380,7 @@ async def test_most_targeted_matcher_wins(
|
||||
async def test_discovered_by_websocket_scan_rejected_by_description_matcher(
|
||||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
||||
) -> None:
|
||||
"""Test a device is discovered from websocket scan rejected by the description matcher."""
|
||||
"""Test websocket scan discovery rejected by the description matcher."""
|
||||
new_usb = [
|
||||
{"domain": "test1", "vid": "3039", "pid": "3039", "description": "*not_it*"}
|
||||
]
|
||||
@@ -418,7 +418,7 @@ async def test_discovered_by_websocket_scan_rejected_by_description_matcher(
|
||||
async def test_discovered_by_websocket_scan_limited_by_serial_number_matcher(
|
||||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
||||
) -> None:
|
||||
"""Test a device is discovered from websocket scan is limited by the serial_number matcher."""
|
||||
"""Test websocket scan discovery is limited by the serial_number matcher."""
|
||||
new_usb = [
|
||||
{
|
||||
"domain": "test1",
|
||||
@@ -462,7 +462,7 @@ async def test_discovered_by_websocket_scan_limited_by_serial_number_matcher(
|
||||
async def test_discovered_by_websocket_scan_rejected_by_serial_number_matcher(
|
||||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
||||
) -> None:
|
||||
"""Test a device is discovered from websocket scan is rejected by the serial_number matcher."""
|
||||
"""Test websocket scan discovery is rejected by the serial_number matcher."""
|
||||
new_usb = [
|
||||
{"domain": "test1", "vid": "3039", "pid": "3039", "serial_number": "123*"}
|
||||
]
|
||||
@@ -500,7 +500,7 @@ async def test_discovered_by_websocket_scan_rejected_by_serial_number_matcher(
|
||||
async def test_discovered_by_websocket_scan_limited_by_manufacturer_matcher(
|
||||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
||||
) -> None:
|
||||
"""Test a device is discovered from websocket scan is limited by the manufacturer matcher."""
|
||||
"""Test websocket scan discovery is limited by the manufacturer matcher."""
|
||||
new_usb = [
|
||||
{
|
||||
"domain": "test1",
|
||||
@@ -544,7 +544,7 @@ async def test_discovered_by_websocket_scan_limited_by_manufacturer_matcher(
|
||||
async def test_discovered_by_websocket_scan_rejected_by_manufacturer_matcher(
|
||||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
||||
) -> None:
|
||||
"""Test a device is discovered from websocket scan is rejected by the manufacturer matcher."""
|
||||
"""Test websocket scan discovery is rejected by the manufacturer matcher."""
|
||||
new_usb = [
|
||||
{
|
||||
"domain": "test1",
|
||||
@@ -587,7 +587,7 @@ async def test_discovered_by_websocket_scan_rejected_by_manufacturer_matcher(
|
||||
async def test_discovered_by_websocket_rejected_with_empty_serial_number_only(
|
||||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
||||
) -> None:
|
||||
"""Test a device is discovered from websocket is rejected with empty serial number."""
|
||||
"""Test websocket discovery is rejected with empty serial number."""
|
||||
new_usb = [
|
||||
{"domain": "test1", "vid": "3039", "pid": "3039", "serial_number": "123*"}
|
||||
]
|
||||
@@ -662,7 +662,7 @@ async def test_discovered_by_websocket_scan_match_vid_only(
|
||||
async def test_discovered_by_websocket_scan_match_vid_wrong_pid(
|
||||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
||||
) -> None:
|
||||
"""Test a device is discovered from websocket scan only matching vid but wrong pid."""
|
||||
"""Test websocket scan discovery matching vid but wrong pid."""
|
||||
new_usb = [{"domain": "test1", "vid": "3039", "pid": "9999"}]
|
||||
|
||||
mock_ports = [
|
||||
@@ -769,7 +769,7 @@ async def test_non_matching_discovered_by_scanner_after_started(
|
||||
async def test_aiousbwatcher_on_wsl_fallback_without_throwing_exception(
|
||||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
||||
) -> None:
|
||||
"""Test that aiousbwatcher on WSL failure results in fallback to scanning without raising an exception."""
|
||||
"""Test aiousbwatcher WSL failure falls back to scanning without exception."""
|
||||
new_usb = [{"domain": "test1", "vid": "3039"}]
|
||||
|
||||
mock_ports = [
|
||||
|
||||
@@ -328,7 +328,7 @@ async def test_change_device_source(
|
||||
device_registry: dr.DeviceRegistry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test remove the device registry configuration entry when the source entity changes."""
|
||||
"""Test remove device registry config entry when source entity changes."""
|
||||
# Configure source entity 1 (with a linked device)
|
||||
source_config_entry_1 = MockConfigEntry()
|
||||
source_config_entry_1.add_to_hass(hass)
|
||||
@@ -403,7 +403,8 @@ async def test_change_device_source(
|
||||
assert await hass.config_entries.async_setup(utility_meter_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Confirm that the configuration entry has not been added to the source entity 1 (current) device registry
|
||||
# Confirm that the configuration entry has not been added
|
||||
# to the source entity 1 (current) device registry
|
||||
current_device = device_registry.async_get(
|
||||
device_id=current_entity_source.device_id
|
||||
)
|
||||
@@ -417,7 +418,8 @@ async def test_change_device_source(
|
||||
):
|
||||
assert utility_meter_entity.device_id == source_entity_1.device_id
|
||||
|
||||
# Change configuration options to use source entity 2 (with a linked device) and reload the integration
|
||||
# Change configuration options to use source entity 2
|
||||
# (with a linked device) and reload the integration
|
||||
previous_entity_source = source_entity_1
|
||||
current_entity_source = source_entity_2
|
||||
|
||||
@@ -435,13 +437,15 @@ async def test_change_device_source(
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Confirm that the configuration entry is not in the source entity 1 (previous) device registry
|
||||
# Confirm that the configuration entry is not in the
|
||||
# source entity 1 (previous) device registry
|
||||
previous_device = device_registry.async_get(
|
||||
device_id=previous_entity_source.device_id
|
||||
)
|
||||
assert utility_meter_config_entry.entry_id not in previous_device.config_entries
|
||||
|
||||
# Confirm that the configuration entry is not in to the source entity 2 (current) device registry
|
||||
# Confirm that the configuration entry is not in
|
||||
# the source entity 2 (current) device registry
|
||||
current_device = device_registry.async_get(
|
||||
device_id=current_entity_source.device_id
|
||||
)
|
||||
@@ -455,7 +459,8 @@ async def test_change_device_source(
|
||||
):
|
||||
assert utility_meter_entity.device_id == source_entity_2.device_id
|
||||
|
||||
# Change configuration options to use source entity 3 (without a device) and reload the integration
|
||||
# Change configuration options to use source entity 3
|
||||
# (without a device) and reload the integration
|
||||
previous_entity_source = source_entity_2
|
||||
current_entity_source = source_entity_3
|
||||
|
||||
@@ -473,7 +478,8 @@ async def test_change_device_source(
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Confirm that the configuration entry has is not in the source entity 2 (previous) device registry
|
||||
# Confirm that the configuration entry is not in the
|
||||
# source entity 2 (previous) device registry
|
||||
previous_device = device_registry.async_get(
|
||||
device_id=previous_entity_source.device_id
|
||||
)
|
||||
@@ -495,7 +501,8 @@ async def test_change_device_source(
|
||||
== []
|
||||
)
|
||||
|
||||
# Change configuration options to use source entity 2 (with a linked device) and reload the integration
|
||||
# Change configuration options to use source entity 2
|
||||
# (with a linked device) and reload the integration
|
||||
previous_entity_source = source_entity_3
|
||||
current_entity_source = source_entity_2
|
||||
|
||||
@@ -513,7 +520,8 @@ async def test_change_device_source(
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Confirm that the configuration entry is not in the source entity 2 (current) device registry
|
||||
# Confirm that the configuration entry is not in the
|
||||
# source entity 2 (current) device registry
|
||||
current_device = device_registry.async_get(
|
||||
device_id=current_entity_source.device_id
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user