Move signal handling out of core to bootstrap (#5815)

* Move signal handling out of core to bootstrap

* Fix tests
This commit is contained in:
Pascal Vizeli 2017-02-09 06:58:45 +01:00 committed by Paulus Schoutsen
parent 7eb4bdc37b
commit 2cbed9cd96
7 changed files with 44 additions and 26 deletions

View file

@ -5,6 +5,7 @@ omit =
homeassistant/__main__.py homeassistant/__main__.py
homeassistant/scripts/*.py homeassistant/scripts/*.py
homeassistant/helpers/typing.py homeassistant/helpers/typing.py
homeassistant/helpers/signal.py
# omit pieces of code that rely on external devices being present # omit pieces of code that rely on external devices being present
homeassistant/components/apcupsd.py homeassistant/components/apcupsd.py

View file

@ -26,6 +26,7 @@ from homeassistant.const import EVENT_COMPONENT_LOADED, PLATFORM_FORMAT
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import (
event_decorators, service, config_per_platform, extract_domain_configs) event_decorators, service, config_per_platform, extract_domain_configs)
from homeassistant.helpers.signal import async_register_signal_handling
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -435,6 +436,7 @@ def async_from_config_dict(config: Dict[str, Any],
yield from hass.async_stop_track_tasks() yield from hass.async_stop_track_tasks()
async_register_signal_handling(hass)
return hass return hass

View file

@ -11,7 +11,6 @@ import enum
import logging import logging
import os import os
import re import re
import signal
import sys import sys
import threading import threading
@ -26,7 +25,7 @@ from homeassistant.const import (
ATTR_SERVICE_CALL_ID, ATTR_SERVICE_DATA, EVENT_CALL_SERVICE, ATTR_SERVICE_CALL_ID, ATTR_SERVICE_DATA, EVENT_CALL_SERVICE,
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
EVENT_SERVICE_EXECUTED, EVENT_SERVICE_REGISTERED, EVENT_STATE_CHANGED, EVENT_SERVICE_EXECUTED, EVENT_SERVICE_REGISTERED, EVENT_STATE_CHANGED,
EVENT_TIME_CHANGED, MATCH_ALL, RESTART_EXIT_CODE, __version__) EVENT_TIME_CHANGED, MATCH_ALL, __version__)
from homeassistant.exceptions import ( from homeassistant.exceptions import (
HomeAssistantError, InvalidEntityFormatError, ShuttingDown) HomeAssistantError, InvalidEntityFormatError, ShuttingDown)
from homeassistant.util.async import ( from homeassistant.util.async import (
@ -150,24 +149,6 @@ class HomeAssistant(object):
_LOGGER.info("Starting Home Assistant") _LOGGER.info("Starting Home Assistant")
self.state = CoreState.starting self.state = CoreState.starting
# Setup signal handling
if sys.platform != 'win32':
def _async_signal_handle(exit_code):
"""Wrap signal handling."""
self.async_add_job(self.async_stop(exit_code))
try:
self.loop.add_signal_handler(
signal.SIGTERM, _async_signal_handle, 0)
except ValueError:
_LOGGER.warning("Could not bind to SIGTERM")
try:
self.loop.add_signal_handler(
signal.SIGHUP, _async_signal_handle, RESTART_EXIT_CODE)
except ValueError:
_LOGGER.warning("Could not bind to SIGHUP")
# pylint: disable=protected-access # pylint: disable=protected-access
self.loop._thread_ident = threading.get_ident() self.loop._thread_ident = threading.get_ident()
_async_create_timer(self) _async_create_timer(self)

View file

@ -0,0 +1,31 @@
"""Signal handling related helpers."""
import logging
import signal
import sys
from homeassistant.core import callback
from homeassistant.const import RESTART_EXIT_CODE
_LOGGER = logging.getLogger(__name__)
@callback
def async_register_signal_handling(hass):
"""Register system signal handler for core."""
if sys.platform != 'win32':
@callback
def async_signal_handle(exit_code):
"""Wrap signal handling."""
hass.async_add_job(hass.async_stop(exit_code))
try:
hass.loop.add_signal_handler(
signal.SIGTERM, async_signal_handle, 0)
except ValueError:
_LOGGER.warning("Could not bind to SIGTERM")
try:
hass.loop.add_signal_handler(
signal.SIGHUP, async_signal_handle, RESTART_EXIT_CODE)
except ValueError:
_LOGGER.warning("Could not bind to SIGHUP")

View file

@ -108,8 +108,7 @@ def async_test_home_assistant(loop):
@asyncio.coroutine @asyncio.coroutine
def mock_async_start(): def mock_async_start():
"""Start the mocking.""" """Start the mocking."""
with patch.object(loop, 'add_signal_handler'), \ with patch('homeassistant.core._async_create_timer'):
patch('homeassistant.core._async_create_timer'):
yield from orig_start() yield from orig_start()
hass.async_start = mock_async_start hass.async_start = mock_async_start

View file

@ -155,7 +155,8 @@ class TestHelpersDiscovery:
assert 'test_component' in self.hass.config.components assert 'test_component' in self.hass.config.components
assert 'switch' in self.hass.config.components assert 'switch' in self.hass.config.components
def test_1st_discovers_2nd_component(self): @patch('homeassistant.bootstrap.async_register_signal_handling')
def test_1st_discovers_2nd_component(self, mock_signal):
"""Test that we don't break if one component discovers the other. """Test that we don't break if one component discovers the other.
If the first component fires a discovery event to setup the If the first component fires a discovery event to setup the

View file

@ -58,7 +58,8 @@ class TestBootstrap:
autospec=True) autospec=True)
@mock.patch('homeassistant.util.location.detect_location_info', @mock.patch('homeassistant.util.location.detect_location_info',
autospec=True, return_value=None) autospec=True, return_value=None)
def test_from_config_file(self, mock_upgrade, mock_detect): @mock.patch('homeassistant.helpers.signal.async_register_signal_handling')
def test_from_config_file(self, mock_upgrade, mock_detect, mock_signal):
"""Test with configuration file.""" """Test with configuration file."""
components = ['browser', 'conversation', 'script'] components = ['browser', 'conversation', 'script']
files = { files = {
@ -289,7 +290,8 @@ class TestBootstrap:
assert 'comp' not in self.hass.config.components assert 'comp' not in self.hass.config.components
@mock.patch('homeassistant.bootstrap.enable_logging') @mock.patch('homeassistant.bootstrap.enable_logging')
def test_home_assistant_core_config_validation(self, log_mock): @mock.patch('homeassistant.helpers.signal.async_register_signal_handling')
def test_home_assistant_core_config_validation(self, log_mock, sig_mock):
"""Test if we pass in wrong information for HA conf.""" """Test if we pass in wrong information for HA conf."""
# Extensive HA conf validation testing is done in test_config.py # Extensive HA conf validation testing is done in test_config.py
assert None is bootstrap.from_config_dict({ assert None is bootstrap.from_config_dict({
@ -393,7 +395,8 @@ class TestBootstrap:
assert loader.get_component('disabled_component') is not None assert loader.get_component('disabled_component') is not None
assert 'disabled_component' in self.hass.config.components assert 'disabled_component' in self.hass.config.components
def test_all_work_done_before_start(self): @mock.patch('homeassistant.bootstrap.async_register_signal_handling')
def test_all_work_done_before_start(self, signal_mock):
"""Test all init work done till start.""" """Test all init work done till start."""
call_order = [] call_order = []