Use voluptuous for graphite (#2929)

* Migrate to voluptuous

* Update tests

* Fix tests and check if Graphite instance is reachable
pull/2953/head
Fabian Affolter 2016-08-24 04:01:46 +02:00 committed by Paulus Schoutsen
parent 6f27d58188
commit 98364248d4
2 changed files with 63 additions and 33 deletions

View File

@ -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

View File

@ -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')