Use voluptuous for graphite (#2929)
* Migrate to voluptuous * Update tests * Fix tests and check if Graphite instance is reachablepull/2953/head
parent
6f27d58188
commit
98364248d4
|
@ -1,5 +1,5 @@
|
||||||
"""
|
"""
|
||||||
Component that sends data to aGraphite installation.
|
Component that sends data to a Graphite installation.
|
||||||
|
|
||||||
For more details about this component, please refer to the documentation at
|
For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/graphite/
|
https://home-assistant.io/components/graphite/
|
||||||
|
@ -10,26 +10,48 @@ import socket
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from homeassistant.const import (
|
import voluptuous as vol
|
||||||
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, EVENT_STATE_CHANGED)
|
|
||||||
from homeassistant.helpers import state
|
from homeassistant.const import (
|
||||||
|
CONF_HOST, CONF_PORT, CONF_PREFIX, EVENT_HOMEASSISTANT_START,
|
||||||
|
EVENT_HOMEASSISTANT_STOP, EVENT_STATE_CHANGED)
|
||||||
|
from homeassistant.helpers import state
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
DOMAIN = "graphite"
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
DEFAULT_HOST = 'localhost'
|
||||||
|
DEFAULT_PORT = 2003
|
||||||
|
DEFAULT_PREFIX = 'ha'
|
||||||
|
DOMAIN = 'graphite'
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = vol.Schema({
|
||||||
|
DOMAIN: vol.Schema({
|
||||||
|
vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
|
||||||
|
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
||||||
|
vol.Optional(CONF_PREFIX, default=DEFAULT_PREFIX): cv.string,
|
||||||
|
}),
|
||||||
|
}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Setup the Graphite feeder."""
|
"""Setup the Graphite feeder."""
|
||||||
graphite_config = config.get('graphite', {})
|
conf = config[DOMAIN]
|
||||||
host = graphite_config.get('host', 'localhost')
|
host = conf.get(CONF_HOST)
|
||||||
prefix = graphite_config.get('prefix', 'ha')
|
prefix = conf.get(CONF_PREFIX)
|
||||||
|
port = conf.get(CONF_PORT)
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
try:
|
try:
|
||||||
port = int(graphite_config.get('port', 2003))
|
sock.connect((host, port))
|
||||||
except ValueError:
|
sock.shutdown(2)
|
||||||
_LOGGER.error('Invalid port specified')
|
_LOGGER.debug('Connection to Graphite possible')
|
||||||
|
except socket.error:
|
||||||
|
_LOGGER.error('Not able to connect to Graphite')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
GraphiteFeeder(hass, host, port, prefix)
|
GraphiteFeeder(hass, host, port, prefix)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
import socket
|
import socket
|
||||||
import unittest
|
import unittest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
import homeassistant.core as ha
|
import homeassistant.core as ha
|
||||||
import homeassistant.components.graphite as graphite
|
import homeassistant.components.graphite as graphite
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
EVENT_STATE_CHANGED,
|
EVENT_STATE_CHANGED, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
|
||||||
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
|
|
||||||
STATE_ON, STATE_OFF)
|
STATE_ON, STATE_OFF)
|
||||||
|
|
||||||
from tests.common import get_test_home_assistant
|
from tests.common import get_test_home_assistant
|
||||||
|
from homeassistant import bootstrap
|
||||||
|
|
||||||
|
|
||||||
class TestGraphite(unittest.TestCase):
|
class TestGraphite(unittest.TestCase):
|
||||||
|
@ -19,22 +19,22 @@ class TestGraphite(unittest.TestCase):
|
||||||
def setup_method(self, method):
|
def setup_method(self, method):
|
||||||
"""Setup things to be run when tests are started."""
|
"""Setup things to be run when tests are started."""
|
||||||
self.hass = get_test_home_assistant()
|
self.hass = get_test_home_assistant()
|
||||||
self.hass.config.latitude = 32.87336
|
|
||||||
self.hass.config.longitude = 117.22743
|
|
||||||
self.gf = graphite.GraphiteFeeder(self.hass, 'foo', 123, 'ha')
|
self.gf = graphite.GraphiteFeeder(self.hass, 'foo', 123, 'ha')
|
||||||
|
|
||||||
def teardown_method(self, method):
|
def teardown_method(self, method):
|
||||||
"""Stop everything that was started."""
|
"""Stop everything that was started."""
|
||||||
self.hass.stop()
|
self.hass.stop()
|
||||||
|
|
||||||
@mock.patch('homeassistant.components.graphite.GraphiteFeeder')
|
@patch('socket.socket')
|
||||||
def test_minimal_config(self, mock_gf):
|
def test_setup(self, mock_socket):
|
||||||
"""Test setup with minimal configuration."""
|
"""Test setup."""
|
||||||
self.assertTrue(graphite.setup(self.hass, {}))
|
assert bootstrap.setup_component(self.hass, 'graphite',
|
||||||
mock_gf.assert_called_once_with(self.hass, 'localhost', 2003, 'ha')
|
{'graphite': {}})
|
||||||
|
mock_socket.assert_called_once_with(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|
||||||
@mock.patch('homeassistant.components.graphite.GraphiteFeeder')
|
@patch('socket.socket')
|
||||||
def test_full_config(self, mock_gf):
|
@patch('homeassistant.components.graphite.GraphiteFeeder')
|
||||||
|
def test_full_config(self, mock_gf, mock_socket):
|
||||||
"""Test setup with full configuration."""
|
"""Test setup with full configuration."""
|
||||||
config = {
|
config = {
|
||||||
'graphite': {
|
'graphite': {
|
||||||
|
@ -43,20 +43,25 @@ class TestGraphite(unittest.TestCase):
|
||||||
'prefix': 'me',
|
'prefix': 'me',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.assertTrue(graphite.setup(self.hass, config))
|
self.assertTrue(graphite.setup(self.hass, config))
|
||||||
mock_gf.assert_called_once_with(self.hass, 'foo', 123, 'me')
|
mock_gf.assert_called_once_with(self.hass, 'foo', 123, 'me')
|
||||||
|
mock_socket.assert_called_once_with(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|
||||||
@mock.patch('homeassistant.components.graphite.GraphiteFeeder')
|
@patch('socket.socket')
|
||||||
def test_config_bad_port(self, mock_gf):
|
@patch('homeassistant.components.graphite.GraphiteFeeder')
|
||||||
|
def test_config_port(self, mock_gf, mock_socket):
|
||||||
"""Test setup with invalid port."""
|
"""Test setup with invalid port."""
|
||||||
config = {
|
config = {
|
||||||
'graphite': {
|
'graphite': {
|
||||||
'host': 'foo',
|
'host': 'foo',
|
||||||
'port': 'wrong',
|
'port': 2003,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.assertFalse(graphite.setup(self.hass, config))
|
|
||||||
self.assertFalse(mock_gf.called)
|
self.assertTrue(graphite.setup(self.hass, config))
|
||||||
|
self.assertTrue(mock_gf.called)
|
||||||
|
mock_socket.assert_called_once_with(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|
||||||
def test_subscribe(self):
|
def test_subscribe(self):
|
||||||
"""Test the subscription."""
|
"""Test the subscription."""
|
||||||
|
@ -87,7 +92,7 @@ class TestGraphite(unittest.TestCase):
|
||||||
self.gf.event_listener('foo')
|
self.gf.event_listener('foo')
|
||||||
mock_queue.put.assert_called_once_with('foo')
|
mock_queue.put.assert_called_once_with('foo')
|
||||||
|
|
||||||
@mock.patch('time.time')
|
@patch('time.time')
|
||||||
def test_report_attributes(self, mock_time):
|
def test_report_attributes(self, mock_time):
|
||||||
"""Test the reporting with attributes."""
|
"""Test the reporting with attributes."""
|
||||||
mock_time.return_value = 12345
|
mock_time.return_value = 12345
|
||||||
|
@ -96,19 +101,21 @@ class TestGraphite(unittest.TestCase):
|
||||||
'baz': True,
|
'baz': True,
|
||||||
'bat': 'NaN',
|
'bat': 'NaN',
|
||||||
}
|
}
|
||||||
|
|
||||||
expected = [
|
expected = [
|
||||||
'ha.entity.state 0.000000 12345',
|
'ha.entity.state 0.000000 12345',
|
||||||
'ha.entity.foo 1.000000 12345',
|
'ha.entity.foo 1.000000 12345',
|
||||||
'ha.entity.bar 2.000000 12345',
|
'ha.entity.bar 2.000000 12345',
|
||||||
'ha.entity.baz 1.000000 12345',
|
'ha.entity.baz 1.000000 12345',
|
||||||
]
|
]
|
||||||
|
|
||||||
state = mock.MagicMock(state=0, attributes=attrs)
|
state = mock.MagicMock(state=0, attributes=attrs)
|
||||||
with mock.patch.object(self.gf, '_send_to_graphite') as mock_send:
|
with mock.patch.object(self.gf, '_send_to_graphite') as mock_send:
|
||||||
self.gf._report_attributes('entity', state)
|
self.gf._report_attributes('entity', state)
|
||||||
actual = mock_send.call_args_list[0][0][0].split('\n')
|
actual = mock_send.call_args_list[0][0][0].split('\n')
|
||||||
self.assertEqual(sorted(expected), sorted(actual))
|
self.assertEqual(sorted(expected), sorted(actual))
|
||||||
|
|
||||||
@mock.patch('time.time')
|
@patch('time.time')
|
||||||
def test_report_with_string_state(self, mock_time):
|
def test_report_with_string_state(self, mock_time):
|
||||||
"""Test the reporting with strings."""
|
"""Test the reporting with strings."""
|
||||||
mock_time.return_value = 12345
|
mock_time.return_value = 12345
|
||||||
|
@ -116,13 +123,14 @@ class TestGraphite(unittest.TestCase):
|
||||||
'ha.entity.foo 1.000000 12345',
|
'ha.entity.foo 1.000000 12345',
|
||||||
'ha.entity.state 1.000000 12345',
|
'ha.entity.state 1.000000 12345',
|
||||||
]
|
]
|
||||||
|
|
||||||
state = mock.MagicMock(state='above_horizon', attributes={'foo': 1.0})
|
state = mock.MagicMock(state='above_horizon', attributes={'foo': 1.0})
|
||||||
with mock.patch.object(self.gf, '_send_to_graphite') as mock_send:
|
with mock.patch.object(self.gf, '_send_to_graphite') as mock_send:
|
||||||
self.gf._report_attributes('entity', state)
|
self.gf._report_attributes('entity', state)
|
||||||
actual = mock_send.call_args_list[0][0][0].split('\n')
|
actual = mock_send.call_args_list[0][0][0].split('\n')
|
||||||
self.assertEqual(sorted(expected), sorted(actual))
|
self.assertEqual(sorted(expected), sorted(actual))
|
||||||
|
|
||||||
@mock.patch('time.time')
|
@patch('time.time')
|
||||||
def test_report_with_binary_state(self, mock_time):
|
def test_report_with_binary_state(self, mock_time):
|
||||||
"""Test the reporting with binary state."""
|
"""Test the reporting with binary state."""
|
||||||
mock_time.return_value = 12345
|
mock_time.return_value = 12345
|
||||||
|
@ -142,7 +150,7 @@ class TestGraphite(unittest.TestCase):
|
||||||
actual = mock_send.call_args_list[0][0][0].split('\n')
|
actual = mock_send.call_args_list[0][0][0].split('\n')
|
||||||
self.assertEqual(sorted(expected), sorted(actual))
|
self.assertEqual(sorted(expected), sorted(actual))
|
||||||
|
|
||||||
@mock.patch('time.time')
|
@patch('time.time')
|
||||||
def test_send_to_graphite_errors(self, mock_time):
|
def test_send_to_graphite_errors(self, mock_time):
|
||||||
"""Test the sending with errors."""
|
"""Test the sending with errors."""
|
||||||
mock_time.return_value = 12345
|
mock_time.return_value = 12345
|
||||||
|
@ -153,7 +161,7 @@ class TestGraphite(unittest.TestCase):
|
||||||
mock_send.side_effect = socket.gaierror
|
mock_send.side_effect = socket.gaierror
|
||||||
self.gf._report_attributes('entity', state)
|
self.gf._report_attributes('entity', state)
|
||||||
|
|
||||||
@mock.patch('socket.socket')
|
@patch('socket.socket')
|
||||||
def test_send_to_graphite(self, mock_socket):
|
def test_send_to_graphite(self, mock_socket):
|
||||||
"""Test the sending of data."""
|
"""Test the sending of data."""
|
||||||
self.gf._send_to_graphite('foo')
|
self.gf._send_to_graphite('foo')
|
||||||
|
|
Loading…
Reference in New Issue