mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
Merge pull request #55673 from home-assistant/rc
This commit is contained in:
commit
33047d7260
@ -342,7 +342,11 @@ def async_enable_logging(
|
||||
err_log_path, backupCount=1
|
||||
)
|
||||
|
||||
err_handler.doRollover()
|
||||
try:
|
||||
err_handler.doRollover()
|
||||
except OSError as err:
|
||||
_LOGGER.error("Error rolling over log file: %s", err)
|
||||
|
||||
err_handler.setLevel(logging.INFO if verbose else logging.WARNING)
|
||||
err_handler.setFormatter(logging.Formatter(fmt, datefmt=datefmt))
|
||||
|
||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
from collections.abc import Iterable, Mapping
|
||||
from functools import wraps
|
||||
import logging
|
||||
from types import ModuleType
|
||||
from typing import Any
|
||||
|
||||
@ -27,7 +28,6 @@ from .exceptions import DeviceNotFound, InvalidDeviceAutomationConfig
|
||||
|
||||
DOMAIN = "device_automation"
|
||||
|
||||
|
||||
DEVICE_TRIGGER_BASE_SCHEMA = cv.TRIGGER_BASE_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_PLATFORM): "device",
|
||||
@ -174,6 +174,13 @@ async def _async_get_device_automations(
|
||||
device_results, InvalidDeviceAutomationConfig
|
||||
):
|
||||
continue
|
||||
if isinstance(device_results, Exception):
|
||||
logging.getLogger(__name__).error(
|
||||
"Unexpected error fetching device %ss",
|
||||
automation_type,
|
||||
exc_info=device_results,
|
||||
)
|
||||
continue
|
||||
for automation in device_results:
|
||||
combined_results[automation["device_id"]].append(automation)
|
||||
|
||||
|
@ -7,6 +7,8 @@ from homeassistant.components.device_automation import (
|
||||
)
|
||||
from homeassistant.const import CONF_DOMAIN
|
||||
|
||||
from .exceptions import InvalidDeviceAutomationConfig
|
||||
|
||||
# mypy: allow-untyped-defs, no-check-untyped-defs
|
||||
|
||||
TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA)
|
||||
@ -17,10 +19,13 @@ async def async_validate_trigger_config(hass, config):
|
||||
platform = await async_get_device_automation_platform(
|
||||
hass, config[CONF_DOMAIN], "trigger"
|
||||
)
|
||||
if hasattr(platform, "async_validate_trigger_config"):
|
||||
return await getattr(platform, "async_validate_trigger_config")(hass, config)
|
||||
if not hasattr(platform, "async_validate_trigger_config"):
|
||||
return platform.TRIGGER_SCHEMA(config)
|
||||
|
||||
return platform.TRIGGER_SCHEMA(config)
|
||||
try:
|
||||
return await getattr(platform, "async_validate_trigger_config")(hass, config)
|
||||
except InvalidDeviceAutomationConfig as err:
|
||||
raise vol.Invalid(str(err) or "Invalid trigger configuration") from err
|
||||
|
||||
|
||||
async def async_attach_trigger(hass, config, action, automation_info):
|
||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
|
||||
from homeassistant.components.switch import DOMAIN, SwitchEntity
|
||||
from homeassistant.const import STATE_OFF, STATE_ON
|
||||
|
||||
from . import ATTR_NEW, CecEntity
|
||||
|
||||
@ -34,17 +35,25 @@ class CecSwitchEntity(CecEntity, SwitchEntity):
|
||||
def turn_on(self, **kwargs) -> None:
|
||||
"""Turn device on."""
|
||||
self._device.turn_on()
|
||||
self._attr_is_on = True
|
||||
self._state = STATE_ON
|
||||
self.schedule_update_ha_state(force_refresh=False)
|
||||
|
||||
def turn_off(self, **kwargs) -> None:
|
||||
"""Turn device off."""
|
||||
self._device.turn_off()
|
||||
self._attr_is_on = False
|
||||
self._state = STATE_OFF
|
||||
self.schedule_update_ha_state(force_refresh=False)
|
||||
|
||||
def toggle(self, **kwargs):
|
||||
"""Toggle the entity."""
|
||||
self._device.toggle()
|
||||
self._attr_is_on = not self._attr_is_on
|
||||
if self._state == STATE_ON:
|
||||
self._state = STATE_OFF
|
||||
else:
|
||||
self._state = STATE_ON
|
||||
self.schedule_update_ha_state(force_refresh=False)
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return True if entity is on."""
|
||||
return self._state == STATE_ON
|
||||
|
@ -118,12 +118,16 @@ async def async_validate_trigger_config(hass, config):
|
||||
|
||||
trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])
|
||||
|
||||
if (
|
||||
not device
|
||||
or device.model not in REMOTES
|
||||
or trigger not in REMOTES[device.model]
|
||||
):
|
||||
raise InvalidDeviceAutomationConfig
|
||||
if not device:
|
||||
raise InvalidDeviceAutomationConfig("Device {config[CONF_DEVICE_ID]} not found")
|
||||
|
||||
if device.model not in REMOTES:
|
||||
raise InvalidDeviceAutomationConfig(
|
||||
f"Device model {device.model} is not a remote"
|
||||
)
|
||||
|
||||
if trigger not in REMOTES[device.model]:
|
||||
raise InvalidDeviceAutomationConfig("Device does not support trigger {trigger}")
|
||||
|
||||
return config
|
||||
|
||||
|
@ -32,6 +32,8 @@ from .const import (
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SENSOR_KEYS = [desc.key for desc in SENSOR_TYPES]
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
vol.All(
|
||||
# Deprecated in Home Assistant 2021.6
|
||||
@ -46,8 +48,8 @@ CONFIG_SCHEMA = vol.Schema(
|
||||
): cv.positive_time_period,
|
||||
vol.Optional(CONF_MANUAL, default=False): cv.boolean,
|
||||
vol.Optional(
|
||||
CONF_MONITORED_CONDITIONS, default=list(SENSOR_TYPES)
|
||||
): vol.All(cv.ensure_list, [vol.In(list(SENSOR_TYPES))]),
|
||||
CONF_MONITORED_CONDITIONS, default=list(SENSOR_KEYS)
|
||||
): vol.All(cv.ensure_list, [vol.In(list(SENSOR_KEYS))]),
|
||||
}
|
||||
)
|
||||
},
|
||||
|
@ -289,7 +289,7 @@ class Scanner:
|
||||
def _async_unsee(self, header_st: str | None, header_location: str | None) -> None:
|
||||
"""If we see a device in a new location, unsee the original location."""
|
||||
if header_st is not None:
|
||||
self.seen.remove((header_st, header_location))
|
||||
self.seen.discard((header_st, header_location))
|
||||
|
||||
async def _async_process_entry(self, headers: Mapping[str, str]) -> None:
|
||||
"""Process SSDP entries."""
|
||||
|
@ -90,7 +90,8 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
||||
sensor
|
||||
for device in account.api.devices.values()
|
||||
for description in SENSOR_TYPES
|
||||
if (sensor := StarlineSensor(account, device, description)).state is not None
|
||||
if (sensor := StarlineSensor(account, device, description)).native_value
|
||||
is not None
|
||||
]
|
||||
async_add_entities(entities)
|
||||
|
||||
|
@ -69,7 +69,7 @@ class TriggerEntity(update_coordinator.CoordinatorEntity):
|
||||
|
||||
# We make a copy so our initial render is 'unknown' and not 'unavailable'
|
||||
self._rendered = dict(self._static_rendered)
|
||||
self._parse_result = set()
|
||||
self._parse_result = {CONF_AVAILABILITY}
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@ -112,7 +112,7 @@ class USBDiscovery:
|
||||
if not sys.platform.startswith("linux"):
|
||||
return
|
||||
info = await system_info.async_get_system_info(self.hass)
|
||||
if info.get("docker") and not info.get("hassio"):
|
||||
if info.get("docker"):
|
||||
return
|
||||
|
||||
from pyudev import ( # pylint: disable=import-outside-toplevel
|
||||
|
@ -326,11 +326,6 @@ class ConfigFlow(BaseZwaveJSFlow, config_entries.ConfigFlow, domain=DOMAIN):
|
||||
device = discovery_info["device"]
|
||||
manufacturer = discovery_info["manufacturer"]
|
||||
description = discovery_info["description"]
|
||||
# The Nortek sticks are a special case since they
|
||||
# have a Z-Wave and a Zigbee radio. We need to reject
|
||||
# the Zigbee radio.
|
||||
if vid == "10C4" and pid == "8A2A" and "Z-Wave" not in description:
|
||||
return self.async_abort(reason="not_zwave_device")
|
||||
# Zooz uses this vid/pid, but so do 2652 sticks
|
||||
if vid == "10C4" and pid == "EA60" and "2652" in description:
|
||||
return self.async_abort(reason="not_zwave_device")
|
||||
|
@ -9,7 +9,7 @@
|
||||
"iot_class": "local_push",
|
||||
"usb": [
|
||||
{"vid":"0658","pid":"0200","known_devices":["Aeotec Z-Stick Gen5+", "Z-WaveMe UZB"]},
|
||||
{"vid":"10C4","pid":"8A2A","known_devices":["Nortek HUSBZB-1"]},
|
||||
{"vid":"10C4","pid":"8A2A","description":"*z-wave*","known_devices":["Nortek HUSBZB-1"]},
|
||||
{"vid":"10C4","pid":"EA60","known_devices":["Aeotec Z-Stick 7", "Silicon Labs UZB-7", "Zooz ZST10 700"]}
|
||||
]
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ from typing import Final
|
||||
|
||||
MAJOR_VERSION: Final = 2021
|
||||
MINOR_VERSION: Final = 9
|
||||
PATCH_VERSION: Final = "1"
|
||||
PATCH_VERSION: Final = "2"
|
||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 8, 0)
|
||||
|
@ -32,7 +32,8 @@ USB = [
|
||||
{
|
||||
"domain": "zwave_js",
|
||||
"vid": "10C4",
|
||||
"pid": "8A2A"
|
||||
"pid": "8A2A",
|
||||
"description": "*z-wave*"
|
||||
},
|
||||
{
|
||||
"domain": "zwave_js",
|
||||
|
@ -14,6 +14,7 @@ from unittest.mock import patch
|
||||
from homeassistant import core
|
||||
from homeassistant.config import get_default_config_dir
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import area_registry, device_registry, entity_registry
|
||||
from homeassistant.helpers.check_config import async_check_ha_config_file
|
||||
from homeassistant.util.yaml import Secrets
|
||||
import homeassistant.util.yaml.loader as yaml_loader
|
||||
@ -229,6 +230,9 @@ async def async_check_config(config_dir):
|
||||
"""Check the HA config."""
|
||||
hass = core.HomeAssistant()
|
||||
hass.config.config_dir = config_dir
|
||||
await area_registry.async_load(hass)
|
||||
await device_registry.async_load(hass)
|
||||
await entity_registry.async_load(hass)
|
||||
components = await async_check_ha_config_file(hass)
|
||||
await hass.async_stop(force=True)
|
||||
return components
|
||||
|
@ -1,4 +1,6 @@
|
||||
"""The test for light device automation."""
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components import device_automation
|
||||
@ -443,6 +445,28 @@ async def test_async_get_device_automations_all_devices_action(
|
||||
assert len(result[device_entry.id]) == 3
|
||||
|
||||
|
||||
async def test_async_get_device_automations_all_devices_action_exception_throw(
|
||||
hass, device_reg, entity_reg, caplog
|
||||
):
|
||||
"""Test we get can fetch all the actions when no device id is passed and can handle one throwing an exception."""
|
||||
await async_setup_component(hass, "device_automation", {})
|
||||
config_entry = MockConfigEntry(domain="test", data={})
|
||||
config_entry.add_to_hass(hass)
|
||||
device_entry = device_reg.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||
)
|
||||
entity_reg.async_get_or_create("light", "test", "5678", device_id=device_entry.id)
|
||||
with patch(
|
||||
"homeassistant.components.light.device_trigger.async_get_triggers",
|
||||
side_effect=KeyError,
|
||||
):
|
||||
result = await device_automation.async_get_device_automations(hass, "trigger")
|
||||
assert device_entry.id in result
|
||||
assert len(result[device_entry.id]) == 0
|
||||
assert "KeyError" in caplog.text
|
||||
|
||||
|
||||
async def test_websocket_get_trigger_capabilities(
|
||||
hass, hass_ws_client, device_reg, entity_reg
|
||||
):
|
||||
|
@ -991,9 +991,6 @@ async def test_location_change_evicts_prior_location_from_cache(hass, aioclient_
|
||||
|
||||
@callback
|
||||
def _callback(*_):
|
||||
import pprint
|
||||
|
||||
pprint.pprint(mock_ssdp_response)
|
||||
hass.async_create_task(listener.async_callback(mock_ssdp_response))
|
||||
|
||||
listener.async_start = _async_callback
|
||||
@ -1050,3 +1047,113 @@ async def test_location_change_evicts_prior_location_from_cache(hass, aioclient_
|
||||
mock_init.mock_calls[0][2]["data"][ssdp.ATTR_SSDP_LOCATION]
|
||||
== mock_good_ip_ssdp_response["location"]
|
||||
)
|
||||
|
||||
|
||||
async def test_location_change_with_overlapping_udn_st_combinations(
|
||||
hass, aioclient_mock
|
||||
):
|
||||
"""Test handling when a UDN and ST broadcast multiple locations."""
|
||||
mock_get_ssdp = {
|
||||
"test_integration": [
|
||||
{"manufacturer": "test_manufacturer", "modelName": "test_model"}
|
||||
]
|
||||
}
|
||||
|
||||
hue_response = """
|
||||
<root xmlns="urn:schemas-upnp-org:device-1-0">
|
||||
<device>
|
||||
<manufacturer>test_manufacturer</manufacturer>
|
||||
<modelName>test_model</modelName>
|
||||
</device>
|
||||
</root>
|
||||
"""
|
||||
|
||||
aioclient_mock.get(
|
||||
"http://192.168.72.1:49154/wps_device.xml",
|
||||
text=hue_response.format(ip_address="192.168.72.1"),
|
||||
)
|
||||
aioclient_mock.get(
|
||||
"http://192.168.72.1:49152/wps_device.xml",
|
||||
text=hue_response.format(ip_address="192.168.72.1"),
|
||||
)
|
||||
ssdp_response_without_location = {
|
||||
"ST": "upnp:rootdevice",
|
||||
"_udn": "uuid:a793d3cc-e802-44fb-84f4-5a30f33115b6",
|
||||
"USN": "uuid:a793d3cc-e802-44fb-84f4-5a30f33115b6::upnp:rootdevice",
|
||||
"EXT": "",
|
||||
}
|
||||
|
||||
port_49154_response = CaseInsensitiveDict(
|
||||
**ssdp_response_without_location,
|
||||
**{"LOCATION": "http://192.168.72.1:49154/wps_device.xml"},
|
||||
)
|
||||
port_49152_response = CaseInsensitiveDict(
|
||||
**ssdp_response_without_location,
|
||||
**{"LOCATION": "http://192.168.72.1:49152/wps_device.xml"},
|
||||
)
|
||||
mock_ssdp_response = port_49154_response
|
||||
|
||||
def _generate_fake_ssdp_listener(*args, **kwargs):
|
||||
listener = SSDPListener(*args, **kwargs)
|
||||
|
||||
async def _async_callback(*_):
|
||||
pass
|
||||
|
||||
@callback
|
||||
def _callback(*_):
|
||||
hass.async_create_task(listener.async_callback(mock_ssdp_response))
|
||||
|
||||
listener.async_start = _async_callback
|
||||
listener.async_search = _callback
|
||||
return listener
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.ssdp.async_get_ssdp",
|
||||
return_value=mock_get_ssdp,
|
||||
), patch(
|
||||
"homeassistant.components.ssdp.SSDPListener",
|
||||
new=_generate_fake_ssdp_listener,
|
||||
), patch.object(
|
||||
hass.config_entries.flow, "async_init"
|
||||
) as mock_init:
|
||||
assert await async_setup_component(hass, ssdp.DOMAIN, {ssdp.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=200))
|
||||
await hass.async_block_till_done()
|
||||
assert len(mock_init.mock_calls) == 1
|
||||
assert mock_init.mock_calls[0][1][0] == "test_integration"
|
||||
assert mock_init.mock_calls[0][2]["context"] == {
|
||||
"source": config_entries.SOURCE_SSDP
|
||||
}
|
||||
assert (
|
||||
mock_init.mock_calls[0][2]["data"][ssdp.ATTR_SSDP_LOCATION]
|
||||
== port_49154_response["location"]
|
||||
)
|
||||
|
||||
mock_init.reset_mock()
|
||||
mock_ssdp_response = port_49152_response
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=400))
|
||||
await hass.async_block_till_done()
|
||||
assert mock_init.mock_calls[0][1][0] == "test_integration"
|
||||
assert mock_init.mock_calls[0][2]["context"] == {
|
||||
"source": config_entries.SOURCE_SSDP
|
||||
}
|
||||
assert (
|
||||
mock_init.mock_calls[0][2]["data"][ssdp.ATTR_SSDP_LOCATION]
|
||||
== port_49152_response["location"]
|
||||
)
|
||||
|
||||
mock_init.reset_mock()
|
||||
mock_ssdp_response = port_49154_response
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=600))
|
||||
await hass.async_block_till_done()
|
||||
assert mock_init.mock_calls[0][1][0] == "test_integration"
|
||||
assert mock_init.mock_calls[0][2]["context"] == {
|
||||
"source": config_entries.SOURCE_SSDP
|
||||
}
|
||||
assert (
|
||||
mock_init.mock_calls[0][2]["data"][ssdp.ATTR_SSDP_LOCATION]
|
||||
== port_49154_response["location"]
|
||||
)
|
||||
|
@ -1038,6 +1038,7 @@ async def test_trigger_entity(hass):
|
||||
"unique_id": "via_list-id",
|
||||
"device_class": "battery",
|
||||
"unit_of_measurement": "%",
|
||||
"availability": "{{ True }}",
|
||||
"state": "{{ trigger.event.data.beer + 1 }}",
|
||||
"picture": "{{ '/local/dogs.png' }}",
|
||||
"icon": "{{ 'mdi:pirate' }}",
|
||||
@ -1197,3 +1198,44 @@ async def test_config_top_level(hass):
|
||||
assert state.state == "5"
|
||||
assert state.attributes["device_class"] == "battery"
|
||||
assert state.attributes["state_class"] == "measurement"
|
||||
|
||||
|
||||
async def test_trigger_entity_available(hass):
|
||||
"""Test trigger entity availability works."""
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
"template",
|
||||
{
|
||||
"template": [
|
||||
{
|
||||
"trigger": {"platform": "event", "event_type": "test_event"},
|
||||
"sensor": [
|
||||
{
|
||||
"name": "Maybe Available",
|
||||
"availability": "{{ trigger and trigger.event.data.beer == 2 }}",
|
||||
"state": "{{ trigger.event.data.beer }}",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Sensors are unknown if never triggered
|
||||
state = hass.states.get("sensor.maybe_available")
|
||||
assert state is not None
|
||||
assert state.state == STATE_UNKNOWN
|
||||
|
||||
hass.bus.async_fire("test_event", {"beer": 2})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("sensor.maybe_available")
|
||||
assert state.state == "2"
|
||||
|
||||
hass.bus.async_fire("test_event", {"beer": 1})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("sensor.maybe_available")
|
||||
assert state.state == "unavailable"
|
||||
|
@ -52,55 +52,6 @@ def mock_venv():
|
||||
yield
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not sys.platform.startswith("linux"),
|
||||
reason="Only works on linux",
|
||||
)
|
||||
async def test_discovered_by_observer_before_started(hass, operating_system):
|
||||
"""Test a device is discovered by the observer before started."""
|
||||
|
||||
async def _mock_monitor_observer_callback(callback):
|
||||
await hass.async_add_executor_job(
|
||||
callback, MagicMock(action="add", device_path="/dev/new")
|
||||
)
|
||||
|
||||
def _create_mock_monitor_observer(monitor, callback, name):
|
||||
hass.async_create_task(_mock_monitor_observer_callback(callback))
|
||||
return MagicMock()
|
||||
|
||||
new_usb = [{"domain": "test1", "vid": "3039", "pid": "3039"}]
|
||||
|
||||
mock_comports = [
|
||||
MagicMock(
|
||||
device=slae_sh_device.device,
|
||||
vid=12345,
|
||||
pid=12345,
|
||||
serial_number=slae_sh_device.serial_number,
|
||||
manufacturer=slae_sh_device.manufacturer,
|
||||
description=slae_sh_device.description,
|
||||
)
|
||||
]
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.usb.async_get_usb", return_value=new_usb
|
||||
), patch(
|
||||
"homeassistant.components.usb.comports", return_value=mock_comports
|
||||
), patch(
|
||||
"pyudev.MonitorObserver", new=_create_mock_monitor_observer
|
||||
):
|
||||
assert await async_setup_component(hass, "usb", {"usb": {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
with patch("homeassistant.components.usb.comports", return_value=[]), patch.object(
|
||||
hass.config_entries.flow, "async_init"
|
||||
) as mock_config_flow:
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(mock_config_flow.mock_calls) == 1
|
||||
assert mock_config_flow.mock_calls[0][1][0] == "test1"
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not sys.platform.startswith("linux"),
|
||||
reason="Only works on linux",
|
||||
|
@ -756,10 +756,7 @@ async def test_usb_discovery_already_running(hass, supervisor, addon_running):
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"discovery_info",
|
||||
[
|
||||
NORTEK_ZIGBEE_DISCOVERY_INFO,
|
||||
CP2652_ZIGBEE_DISCOVERY_INFO,
|
||||
],
|
||||
[CP2652_ZIGBEE_DISCOVERY_INFO],
|
||||
)
|
||||
async def test_abort_usb_discovery_aborts_specific_devices(
|
||||
hass, supervisor, addon_options, discovery_info
|
||||
|
@ -27,14 +27,23 @@ async def apply_stop_hass(stop_hass):
|
||||
"""Make sure all hass are stopped."""
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_is_file():
|
||||
"""Mock is_file."""
|
||||
# All files exist except for the old entity registry file
|
||||
with patch(
|
||||
"os.path.isfile", lambda path: not path.endswith("entity_registry.yaml")
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
def normalize_yaml_files(check_dict):
|
||||
"""Remove configuration path from ['yaml_files']."""
|
||||
root = get_test_config_dir()
|
||||
return [key.replace(root, "...") for key in sorted(check_dict["yaml_files"].keys())]
|
||||
|
||||
|
||||
@patch("os.path.isfile", return_value=True)
|
||||
def test_bad_core_config(isfile_patch, loop):
|
||||
def test_bad_core_config(mock_is_file, loop):
|
||||
"""Test a bad core config setup."""
|
||||
files = {YAML_CONFIG_FILE: BAD_CORE_CONFIG}
|
||||
with patch_yaml_files(files):
|
||||
@ -43,8 +52,7 @@ def test_bad_core_config(isfile_patch, loop):
|
||||
assert res["except"]["homeassistant"][1] == {"unit_system": "bad"}
|
||||
|
||||
|
||||
@patch("os.path.isfile", return_value=True)
|
||||
def test_config_platform_valid(isfile_patch, loop):
|
||||
def test_config_platform_valid(mock_is_file, loop):
|
||||
"""Test a valid platform setup."""
|
||||
files = {YAML_CONFIG_FILE: BASE_CONFIG + "light:\n platform: demo"}
|
||||
with patch_yaml_files(files):
|
||||
@ -57,8 +65,7 @@ def test_config_platform_valid(isfile_patch, loop):
|
||||
assert len(res["yaml_files"]) == 1
|
||||
|
||||
|
||||
@patch("os.path.isfile", return_value=True)
|
||||
def test_component_platform_not_found(isfile_patch, loop):
|
||||
def test_component_platform_not_found(mock_is_file, loop):
|
||||
"""Test errors if component or platform not found."""
|
||||
# Make sure they don't exist
|
||||
files = {YAML_CONFIG_FILE: BASE_CONFIG + "beer:"}
|
||||
@ -89,8 +96,7 @@ def test_component_platform_not_found(isfile_patch, loop):
|
||||
assert len(res["yaml_files"]) == 1
|
||||
|
||||
|
||||
@patch("os.path.isfile", return_value=True)
|
||||
def test_secrets(isfile_patch, loop):
|
||||
def test_secrets(mock_is_file, loop):
|
||||
"""Test secrets config checking method."""
|
||||
secrets_path = get_test_config_dir("secrets.yaml")
|
||||
|
||||
@ -121,8 +127,7 @@ def test_secrets(isfile_patch, loop):
|
||||
]
|
||||
|
||||
|
||||
@patch("os.path.isfile", return_value=True)
|
||||
def test_package_invalid(isfile_patch, loop):
|
||||
def test_package_invalid(mock_is_file, loop):
|
||||
"""Test an invalid package."""
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BASE_CONFIG + (" packages:\n p1:\n" ' group: ["a"]')
|
||||
|
@ -56,11 +56,14 @@ async def test_home_assistant_core_config_validation(hass):
|
||||
assert result is None
|
||||
|
||||
|
||||
async def test_async_enable_logging(hass):
|
||||
async def test_async_enable_logging(hass, caplog):
|
||||
"""Test to ensure logging is migrated to the queue handlers."""
|
||||
with patch("logging.getLogger"), patch(
|
||||
"homeassistant.bootstrap.async_activate_log_queue_handler"
|
||||
) as mock_async_activate_log_queue_handler:
|
||||
) as mock_async_activate_log_queue_handler, patch(
|
||||
"homeassistant.bootstrap.logging.handlers.RotatingFileHandler.doRollover",
|
||||
side_effect=OSError,
|
||||
):
|
||||
bootstrap.async_enable_logging(hass)
|
||||
mock_async_activate_log_queue_handler.assert_called_once()
|
||||
mock_async_activate_log_queue_handler.reset_mock()
|
||||
@ -75,6 +78,8 @@ async def test_async_enable_logging(hass):
|
||||
for f in glob.glob("testing_config/home-assistant.log*"):
|
||||
os.remove(f)
|
||||
|
||||
assert "Error rolling over log file" in caplog.text
|
||||
|
||||
|
||||
async def test_load_hassio(hass):
|
||||
"""Test that we load Hass.io component."""
|
||||
|
Loading…
x
Reference in New Issue
Block a user