diff --git a/tests/test_core.py b/tests/test_core.py index 5ebfc070ca2..541f75e6343 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6,7 +6,6 @@ import functools import logging import os from tempfile import TemporaryDirectory -import unittest import pytest import pytz @@ -33,16 +32,16 @@ from homeassistant.const import ( __version__, ) import homeassistant.core as ha -from homeassistant.exceptions import InvalidEntityFormatError, InvalidStateError +from homeassistant.exceptions import ( + InvalidEntityFormatError, + InvalidStateError, + ServiceNotFound, +) import homeassistant.util.dt as dt_util from homeassistant.util.unit_system import METRIC_SYSTEM from tests.async_mock import MagicMock, Mock, PropertyMock, patch -from tests.common import ( - async_capture_events, - async_mock_service, - get_test_home_assistant, -) +from tests.common import async_capture_events, async_mock_service PST = pytz.timezone("America/Los_Angeles") @@ -337,7 +336,7 @@ def test_state_as_dict(): assert state.as_dict() is state.as_dict() -async def test_add_remove_listener(hass): +async def test_eventbus_add_remove_listener(hass): """Test remove_listener method.""" old_count = len(hass.bus.async_listeners()) @@ -356,7 +355,7 @@ async def test_add_remove_listener(hass): unsub() -async def test_unsubscribe_listener(hass): +async def test_eventbus_unsubscribe_listener(hass): """Test unsubscribe listener from returned function.""" calls = [] @@ -380,7 +379,7 @@ async def test_unsubscribe_listener(hass): assert len(calls) == 1 -async def test_listen_once_event_with_callback(hass): +async def test_eventbus_listen_once_event_with_callback(hass): """Test listen_once_event method.""" runs = [] @@ -398,7 +397,7 @@ async def test_listen_once_event_with_callback(hass): assert len(runs) == 1 -async def test_listen_once_event_with_coroutine(hass): +async def test_eventbus_listen_once_event_with_coroutine(hass): """Test listen_once_event method.""" runs = [] @@ -415,7 +414,7 @@ async def test_listen_once_event_with_coroutine(hass): assert len(runs) == 1 -async def test_listen_once_event_with_thread(hass): +async def test_eventbus_listen_once_event_with_thread(hass): """Test listen_once_event method.""" runs = [] @@ -432,7 +431,7 @@ async def test_listen_once_event_with_thread(hass): assert len(runs) == 1 -async def test_thread_event_listener(hass): +async def test_eventbus_thread_event_listener(hass): """Test thread event listener.""" thread_calls = [] @@ -445,7 +444,7 @@ async def test_thread_event_listener(hass): assert len(thread_calls) == 1 -async def test_callback_event_listener(hass): +async def test_eventbus_callback_event_listener(hass): """Test callback event listener.""" callback_calls = [] @@ -459,7 +458,7 @@ async def test_callback_event_listener(hass): assert len(callback_calls) == 1 -async def test_coroutine_event_listener(hass): +async def test_eventbus_coroutine_event_listener(hass): """Test coroutine event listener.""" coroutine_calls = [] @@ -550,117 +549,92 @@ def test_state_repr(): ) -class TestStateMachine(unittest.TestCase): - """Test State machine methods.""" +async def test_statemachine_is_state(hass): + """Test is_state method.""" + hass.states.async_set("light.bowl", "on", {}) + assert hass.states.is_state("light.Bowl", "on") + assert not hass.states.is_state("light.Bowl", "off") + assert not hass.states.is_state("light.Non_existing", "on") - # pylint: disable=invalid-name - def setUp(self): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.states = self.hass.states - self.states.set("light.Bowl", "on") - self.states.set("switch.AC", "off") - # pylint: disable=invalid-name - def tearDown(self): - """Stop down stuff we started.""" - self.hass.stop() +async def test_statemachine_entity_ids(hass): + """Test get_entity_ids method.""" + hass.states.async_set("light.bowl", "on", {}) + hass.states.async_set("SWITCH.AC", "off", {}) + ent_ids = hass.states.async_entity_ids() + assert len(ent_ids) == 2 + assert "light.bowl" in ent_ids + assert "switch.ac" in ent_ids - def test_is_state(self): - """Test is_state method.""" - assert self.states.is_state("light.Bowl", "on") - assert not self.states.is_state("light.Bowl", "off") - assert not self.states.is_state("light.Non_existing", "on") + ent_ids = hass.states.async_entity_ids("light") + assert len(ent_ids) == 1 + assert "light.bowl" in ent_ids - def test_entity_ids(self): - """Test get_entity_ids method.""" - ent_ids = self.states.entity_ids() - assert len(ent_ids) == 2 - assert "light.bowl" in ent_ids - assert "switch.ac" in ent_ids + states = sorted(state.entity_id for state in hass.states.async_all()) + assert states == ["light.bowl", "switch.ac"] - ent_ids = self.states.entity_ids("light") - assert len(ent_ids) == 1 - assert "light.bowl" in ent_ids - def test_all(self): - """Test everything.""" - states = sorted(state.entity_id for state in self.states.all()) - assert ["light.bowl", "switch.ac"] == states +async def test_statemachine_remove(hass): + """Test remove method.""" + hass.states.async_set("light.bowl", "on", {}) + events = async_capture_events(hass, EVENT_STATE_CHANGED) - def test_remove(self): - """Test remove method.""" - events = [] + assert "light.bowl" in hass.states.async_entity_ids() + assert hass.states.async_remove("light.bowl") + await hass.async_block_till_done() - @ha.callback - def callback(event): - events.append(event) + assert "light.bowl" not in hass.states.async_entity_ids() + assert len(events) == 1 + assert events[0].data.get("entity_id") == "light.bowl" + assert events[0].data.get("old_state") is not None + assert events[0].data["old_state"].entity_id == "light.bowl" + assert events[0].data.get("new_state") is None - self.hass.bus.listen(EVENT_STATE_CHANGED, callback) + # If it does not exist, we should get False + assert not hass.states.async_remove("light.Bowl") + await hass.async_block_till_done() + assert len(events) == 1 - assert "light.bowl" in self.states.entity_ids() - assert self.states.remove("light.bowl") - self.hass.block_till_done() - assert "light.bowl" not in self.states.entity_ids() - assert len(events) == 1 - assert events[0].data.get("entity_id") == "light.bowl" - assert events[0].data.get("old_state") is not None - assert events[0].data["old_state"].entity_id == "light.bowl" - assert events[0].data.get("new_state") is None +async def test_statemachine_case_insensitivty(hass): + """Test insensitivty.""" + events = async_capture_events(hass, EVENT_STATE_CHANGED) - # If it does not exist, we should get False - assert not self.states.remove("light.Bowl") - self.hass.block_till_done() - assert len(events) == 1 + hass.states.async_set("light.BOWL", "off") + await hass.async_block_till_done() - def test_case_insensitivty(self): - """Test insensitivty.""" - runs = [] + assert hass.states.is_state("light.bowl", "off") + assert len(events) == 1 - @ha.callback - def callback(event): - runs.append(event) - self.hass.bus.listen(EVENT_STATE_CHANGED, callback) +async def test_statemachine_last_changed_not_updated_on_same_state(hass): + """Test to not update the existing, same state.""" + hass.states.async_set("light.bowl", "on", {}) + state = hass.states.get("light.Bowl") - self.states.set("light.BOWL", "off") - self.hass.block_till_done() + future = dt_util.utcnow() + timedelta(hours=10) - assert self.states.is_state("light.bowl", "off") - assert len(runs) == 1 + with patch("homeassistant.util.dt.utcnow", return_value=future): + hass.states.async_set("light.Bowl", "on", {"attr": "triggers_change"}) + await hass.async_block_till_done() - def test_last_changed_not_updated_on_same_state(self): - """Test to not update the existing, same state.""" - state = self.states.get("light.Bowl") + state2 = hass.states.get("light.Bowl") + assert state2 is not None + assert state.last_changed == state2.last_changed - future = dt_util.utcnow() + timedelta(hours=10) - with patch("homeassistant.util.dt.utcnow", return_value=future): - self.states.set("light.Bowl", "on", {"attr": "triggers_change"}) - self.hass.block_till_done() +async def test_statemachine_force_update(hass): + """Test force update option.""" + hass.states.async_set("light.bowl", "on", {}) + events = async_capture_events(hass, EVENT_STATE_CHANGED) - state2 = self.states.get("light.Bowl") - assert state2 is not None - assert state.last_changed == state2.last_changed + hass.states.async_set("light.bowl", "on") + await hass.async_block_till_done() + assert len(events) == 0 - def test_force_update(self): - """Test force update option.""" - events = [] - - @ha.callback - def callback(event): - events.append(event) - - self.hass.bus.listen(EVENT_STATE_CHANGED, callback) - - self.states.set("light.bowl", "on") - self.hass.block_till_done() - assert len(events) == 0 - - self.states.set("light.bowl", "on", None, True) - self.hass.block_till_done() - assert len(events) == 1 + hass.states.async_set("light.bowl", "on", None, True) + await hass.async_block_till_done() + assert len(events) == 1 def test_service_call_repr(): @@ -675,202 +649,154 @@ def test_service_call_repr(): ) -class TestServiceRegistry(unittest.TestCase): - """Test ServicerRegistry methods.""" +async def test_serviceregistry_has_service(hass): + """Test has_service method.""" + hass.services.async_register("test_domain", "test_service", lambda call: None) + assert len(hass.services.async_services()) == 1 + assert hass.services.has_service("tesT_domaiN", "tesT_servicE") + assert not hass.services.has_service("test_domain", "non_existing") + assert not hass.services.has_service("non_existing", "test_service") - # pylint: disable=invalid-name - def setUp(self): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.services = self.hass.services - @ha.callback - def mock_service(call): - pass +async def test_serviceregistry_call_with_blocking_done_in_time(hass): + """Test call with blocking.""" + registered_events = async_capture_events(hass, EVENT_SERVICE_REGISTERED) + calls = async_mock_service(hass, "test_domain", "register_calls") + await hass.async_block_till_done() - self.services.register("Test_Domain", "TEST_SERVICE", mock_service) + assert len(registered_events) == 1 + assert registered_events[0].data["domain"] == "test_domain" + assert registered_events[0].data["service"] == "register_calls" - self.calls_register = [] + assert await hass.services.async_call( + "test_domain", "REGISTER_CALLS", blocking=True + ) + assert len(calls) == 1 - @ha.callback - def mock_event_register(event): - """Mock register event.""" - self.calls_register.append(event) - self.hass.bus.listen(EVENT_SERVICE_REGISTERED, mock_event_register) +async def test_serviceregistry_call_non_existing_with_blocking(hass): + """Test non-existing with blocking.""" + with pytest.raises(ha.ServiceNotFound): + await hass.services.async_call("test_domain", "i_do_not_exist", blocking=True) - # pylint: disable=invalid-name - def tearDown(self): - """Stop down stuff we started.""" - self.hass.stop() - def test_has_service(self): - """Test has_service method.""" - assert self.services.has_service("tesT_domaiN", "tesT_servicE") - assert not self.services.has_service("test_domain", "non_existing") - assert not self.services.has_service("non_existing", "test_service") +async def test_serviceregistry_async_service(hass): + """Test registering and calling an async service.""" + calls = [] - def test_services(self): - """Test services.""" - assert len(self.services.services) == 1 + async def service_handler(call): + """Service handler coroutine.""" + calls.append(call) - def test_call_with_blocking_done_in_time(self): - """Test call with blocking.""" - calls = [] + hass.services.async_register("test_domain", "register_calls", service_handler) - @ha.callback - def service_handler(call): - """Service handler.""" - calls.append(call) + assert await hass.services.async_call( + "test_domain", "REGISTER_CALLS", blocking=True + ) + assert len(calls) == 1 - self.services.register("test_domain", "register_calls", service_handler) - self.hass.block_till_done() - assert len(self.calls_register) == 1 - assert self.calls_register[-1].data["domain"] == "test_domain" - assert self.calls_register[-1].data["service"] == "register_calls" +async def test_serviceregistry_async_service_partial(hass): + """Test registering and calling an wrapped async service.""" + calls = [] - assert self.services.call("test_domain", "REGISTER_CALLS", blocking=True) - assert len(calls) == 1 + async def service_handler(call): + """Service handler coroutine.""" + calls.append(call) - def test_call_non_existing_with_blocking(self): - """Test non-existing with blocking.""" - with pytest.raises(ha.ServiceNotFound): - self.services.call("test_domain", "i_do_not_exist", blocking=True) + hass.services.async_register( + "test_domain", "register_calls", functools.partial(service_handler) + ) + await hass.async_block_till_done() - def test_async_service(self): - """Test registering and calling an async service.""" - calls = [] + assert await hass.services.async_call( + "test_domain", "REGISTER_CALLS", blocking=True + ) + assert len(calls) == 1 - async def service_handler(call): - """Service handler coroutine.""" - calls.append(call) - self.services.register("test_domain", "register_calls", service_handler) - self.hass.block_till_done() +async def test_serviceregistry_callback_service(hass): + """Test registering and calling an async service.""" + calls = [] - assert len(self.calls_register) == 1 - assert self.calls_register[-1].data["domain"] == "test_domain" - assert self.calls_register[-1].data["service"] == "register_calls" + @ha.callback + def service_handler(call): + """Service handler coroutine.""" + calls.append(call) - assert self.services.call("test_domain", "REGISTER_CALLS", blocking=True) - self.hass.block_till_done() - assert len(calls) == 1 + hass.services.async_register("test_domain", "register_calls", service_handler) - def test_async_service_partial(self): - """Test registering and calling an wrapped async service.""" - calls = [] + assert await hass.services.async_call( + "test_domain", "REGISTER_CALLS", blocking=True + ) + assert len(calls) == 1 - async def service_handler(call): - """Service handler coroutine.""" - calls.append(call) - self.services.register( - "test_domain", "register_calls", functools.partial(service_handler) +async def test_serviceregistry_remove_service(hass): + """Test remove service.""" + calls_remove = async_capture_events(hass, EVENT_SERVICE_REMOVED) + + hass.services.async_register("test_domain", "test_service", lambda call: None) + assert hass.services.has_service("test_Domain", "test_Service") + + hass.services.async_remove("test_Domain", "test_Service") + await hass.async_block_till_done() + + assert not hass.services.has_service("test_Domain", "test_Service") + assert len(calls_remove) == 1 + assert calls_remove[-1].data["domain"] == "test_domain" + assert calls_remove[-1].data["service"] == "test_service" + + +async def test_serviceregistry_service_that_not_exists(hass): + """Test remove service that not exists.""" + calls_remove = async_capture_events(hass, EVENT_SERVICE_REMOVED) + assert not hass.services.has_service("test_xxx", "test_yyy") + hass.services.async_remove("test_xxx", "test_yyy") + await hass.async_block_till_done() + assert len(calls_remove) == 0 + + with pytest.raises(ServiceNotFound): + await hass.services.async_call("test_do_not", "exist", {}) + + +async def test_serviceregistry_async_service_raise_exception(hass): + """Test registering and calling an async service raise exception.""" + + async def service_handler(_): + """Service handler coroutine.""" + raise ValueError + + hass.services.async_register("test_domain", "register_calls", service_handler) + + with pytest.raises(ValueError): + assert await hass.services.async_call( + "test_domain", "REGISTER_CALLS", blocking=True ) - self.hass.block_till_done() - assert len(self.calls_register) == 1 - assert self.calls_register[-1].data["domain"] == "test_domain" - assert self.calls_register[-1].data["service"] == "register_calls" + # Non-blocking service call never throw exception + await hass.services.async_call("test_domain", "REGISTER_CALLS", blocking=False) + await hass.async_block_till_done() - assert self.services.call("test_domain", "REGISTER_CALLS", blocking=True) - self.hass.block_till_done() - assert len(calls) == 1 - def test_callback_service(self): - """Test registering and calling an async service.""" - calls = [] +async def test_serviceregistry_callback_service_raise_exception(hass): + """Test registering and calling an callback service raise exception.""" - @ha.callback - def service_handler(call): - """Service handler coroutine.""" - calls.append(call) + @ha.callback + def service_handler(_): + """Service handler coroutine.""" + raise ValueError - self.services.register("test_domain", "register_calls", service_handler) - self.hass.block_till_done() + hass.services.async_register("test_domain", "register_calls", service_handler) - assert len(self.calls_register) == 1 - assert self.calls_register[-1].data["domain"] == "test_domain" - assert self.calls_register[-1].data["service"] == "register_calls" + with pytest.raises(ValueError): + assert await hass.services.async_call( + "test_domain", "REGISTER_CALLS", blocking=True + ) - assert self.services.call("test_domain", "REGISTER_CALLS", blocking=True) - self.hass.block_till_done() - assert len(calls) == 1 - - def test_remove_service(self): - """Test remove service.""" - calls_remove = [] - - @ha.callback - def mock_event_remove(event): - """Mock register event.""" - calls_remove.append(event) - - self.hass.bus.listen(EVENT_SERVICE_REMOVED, mock_event_remove) - - assert self.services.has_service("test_Domain", "test_Service") - - self.services.remove("test_Domain", "test_Service") - self.hass.block_till_done() - - assert not self.services.has_service("test_Domain", "test_Service") - assert len(calls_remove) == 1 - assert calls_remove[-1].data["domain"] == "test_domain" - assert calls_remove[-1].data["service"] == "test_service" - - def test_remove_service_that_not_exists(self): - """Test remove service that not exists.""" - calls_remove = [] - - @ha.callback - def mock_event_remove(event): - """Mock register event.""" - calls_remove.append(event) - - self.hass.bus.listen(EVENT_SERVICE_REMOVED, mock_event_remove) - - assert not self.services.has_service("test_xxx", "test_yyy") - self.services.remove("test_xxx", "test_yyy") - self.hass.block_till_done() - assert len(calls_remove) == 0 - - def test_async_service_raise_exception(self): - """Test registering and calling an async service raise exception.""" - - async def service_handler(_): - """Service handler coroutine.""" - raise ValueError - - self.services.register("test_domain", "register_calls", service_handler) - self.hass.block_till_done() - - with pytest.raises(ValueError): - assert self.services.call("test_domain", "REGISTER_CALLS", blocking=True) - self.hass.block_till_done() - - # Non-blocking service call never throw exception - self.services.call("test_domain", "REGISTER_CALLS", blocking=False) - self.hass.block_till_done() - - def test_callback_service_raise_exception(self): - """Test registering and calling an callback service raise exception.""" - - @ha.callback - def service_handler(_): - """Service handler coroutine.""" - raise ValueError - - self.services.register("test_domain", "register_calls", service_handler) - self.hass.block_till_done() - - with pytest.raises(ValueError): - assert self.services.call("test_domain", "REGISTER_CALLS", blocking=True) - self.hass.block_till_done() - - # Non-blocking service call never throw exception - self.services.call("test_domain", "REGISTER_CALLS", blocking=False) - self.hass.block_till_done() + # Non-blocking service call never throw exception + await hass.services.async_call("test_domain", "REGISTER_CALLS", blocking=False) + await hass.async_block_till_done() def test_config_defaults():