From 57f32fa629878717c3659312bf757f264082061e Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Wed, 19 Oct 2016 03:10:28 +0200 Subject: [PATCH] Fixup device_tracekt.mqtt voluptuous & unit tests (#3904) --- .../components/device_tracker/__init__.py | 16 +- .../components/device_tracker/mqtt.py | 3 +- homeassistant/components/mqtt/__init__.py | 12 +- homeassistant/helpers/config_validation.py | 3 +- .../components/device_tracker/test_asuswrt.py | 14 +- .../device_tracker/test_owntracks.py | 194 ++++++++++-------- 6 files changed, 137 insertions(+), 105 deletions(-) diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 72698e189ff..5ea3690852a 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -68,15 +68,11 @@ ATTR_ATTRIBUTES = 'attributes' PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ vol.Optional(CONF_SCAN_INTERVAL): cv.positive_int, # seconds -}, extra=vol.ALLOW_EXTRA) - -_CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.All(cv.ensure_list, [ - vol.Schema({ - vol.Optional(CONF_TRACK_NEW, default=DEFAULT_TRACK_NEW): cv.boolean, - vol.Optional( - CONF_CONSIDER_HOME, default=timedelta(seconds=180)): vol.All( - cv.time_period, cv.positive_timedelta) - }, extra=vol.ALLOW_EXTRA)])}, extra=vol.ALLOW_EXTRA) + vol.Optional(CONF_TRACK_NEW, default=DEFAULT_TRACK_NEW): cv.boolean, + vol.Optional(CONF_CONSIDER_HOME, + default=timedelta(seconds=DEFAULT_CONSIDER_HOME)): vol.All( + cv.time_period, cv.positive_timedelta) +}) DISCOVERY_PLATFORMS = { SERVICE_NETGEAR: 'netgear', @@ -116,7 +112,7 @@ def setup(hass: HomeAssistantType, config: ConfigType): yaml_path = hass.config.path(YAML_DEVICES) try: - conf = _CONFIG_SCHEMA(config).get(DOMAIN, []) + conf = config.get(DOMAIN, []) except vol.Invalid as ex: log_exception(ex, DOMAIN, config) return False diff --git a/homeassistant/components/device_tracker/mqtt.py b/homeassistant/components/device_tracker/mqtt.py index 2318eb44dd1..f9a85da98b2 100644 --- a/homeassistant/components/device_tracker/mqtt.py +++ b/homeassistant/components/device_tracker/mqtt.py @@ -11,13 +11,14 @@ import voluptuous as vol import homeassistant.components.mqtt as mqtt from homeassistant.const import CONF_DEVICES from homeassistant.components.mqtt import CONF_QOS +from homeassistant.components.device_tracker import PLATFORM_SCHEMA import homeassistant.helpers.config_validation as cv DEPENDENCIES = ['mqtt'] _LOGGER = logging.getLogger(__name__) -PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(mqtt.SCHEMA_BASE).extend({ vol.Required(CONF_DEVICES): {cv.string: mqtt.valid_subscribe_topic}, }) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index bc7977ae129..307b287ea0d 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -18,8 +18,7 @@ from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import template, config_validation as cv from homeassistant.helpers.event import threaded_listener_factory from homeassistant.const import ( - EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, - CONF_PLATFORM, CONF_SCAN_INTERVAL, CONF_VALUE_TEMPLATE) + EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, CONF_VALUE_TEMPLATE) _LOGGER = logging.getLogger(__name__) @@ -107,12 +106,11 @@ CONFIG_SCHEMA = vol.Schema({ }), }, extra=vol.ALLOW_EXTRA) -MQTT_BASE_PLATFORM_SCHEMA = vol.Schema({ - vol.Required(CONF_PLATFORM): DOMAIN, - vol.Optional(CONF_SCAN_INTERVAL): - vol.All(vol.Coerce(int), vol.Range(min=1)), +SCHEMA_BASE = { vol.Optional(CONF_QOS, default=DEFAULT_QOS): _VALID_QOS_SCHEMA, -}) +} + +MQTT_BASE_PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend(SCHEMA_BASE) # Sensor type platforms subscribe to MQTT events MQTT_RO_PLATFORM_SCHEMA = MQTT_BASE_PLATFORM_SCHEMA.extend({ diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 1d368a37d3c..dcbbbb4b3db 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -358,7 +358,8 @@ def key_dependency(key, dependency): PLATFORM_SCHEMA = vol.Schema({ vol.Required(CONF_PLATFORM): string, - CONF_SCAN_INTERVAL: vol.All(vol.Coerce(int), vol.Range(min=1)), + vol.Optional(CONF_SCAN_INTERVAL): + vol.All(vol.Coerce(int), vol.Range(min=1)), }, extra=vol.ALLOW_EXTRA) EVENT_SCHEMA = vol.Schema({ diff --git a/tests/components/device_tracker/test_asuswrt.py b/tests/components/device_tracker/test_asuswrt.py index 480c76d52b3..ad42fd9d9a6 100644 --- a/tests/components/device_tracker/test_asuswrt.py +++ b/tests/components/device_tracker/test_asuswrt.py @@ -1,5 +1,6 @@ """The tests for the ASUSWRT device tracker platform.""" import os +from datetime import timedelta import unittest from unittest import mock @@ -7,8 +8,11 @@ import voluptuous as vol from homeassistant.bootstrap import setup_component from homeassistant.components import device_tracker +from homeassistant.components.device_tracker import ( + CONF_CONSIDER_HOME, CONF_TRACK_NEW) from homeassistant.components.device_tracker.asuswrt import ( - CONF_PROTOCOL, CONF_MODE, CONF_PUB_KEY, PLATFORM_SCHEMA, DOMAIN) + CONF_PROTOCOL, CONF_MODE, CONF_PUB_KEY, DOMAIN, + PLATFORM_SCHEMA) from homeassistant.const import (CONF_PLATFORM, CONF_PASSWORD, CONF_USERNAME, CONF_HOST) @@ -70,7 +74,9 @@ class TestComponentsDeviceTrackerASUSWRT(unittest.TestCase): CONF_PLATFORM: 'asuswrt', CONF_HOST: 'fake_host', CONF_USERNAME: 'fake_user', - CONF_PASSWORD: 'fake_pass' + CONF_PASSWORD: 'fake_pass', + CONF_TRACK_NEW: True, + CONF_CONSIDER_HOME: timedelta(seconds=180) } } @@ -93,7 +99,9 @@ class TestComponentsDeviceTrackerASUSWRT(unittest.TestCase): CONF_PLATFORM: 'asuswrt', CONF_HOST: 'fake_host', CONF_USERNAME: 'fake_user', - CONF_PUB_KEY: FAKEFILE + CONF_PUB_KEY: FAKEFILE, + CONF_TRACK_NEW: True, + CONF_CONSIDER_HOME: timedelta(seconds=180) } } diff --git a/tests/components/device_tracker/test_owntracks.py b/tests/components/device_tracker/test_owntracks.py index 9ee9c80dc43..38aae9021ec 100644 --- a/tests/components/device_tracker/test_owntracks.py +++ b/tests/components/device_tracker/test_owntracks.py @@ -12,7 +12,8 @@ from homeassistant.const import (STATE_NOT_HOME, CONF_PLATFORM) import homeassistant.components.device_tracker.owntracks as owntracks from tests.common import ( - get_test_home_assistant, mock_mqtt_component, fire_mqtt_message) + assert_setup_component, get_test_home_assistant, mock_mqtt_component, + fire_mqtt_message) USER = 'greg' DEVICE = 'phone' @@ -207,20 +208,60 @@ MOCK_ENCRYPTED_LOCATION_MESSAGE = { } -class TestDeviceTrackerOwnTracks(unittest.TestCase): +class BaseMQTT(unittest.TestCase): + """Base MQTT assert functions.""" + + hass = None + + def send_message(self, topic, message, corrupt=False): + """Test the sending of a message.""" + str_message = json.dumps(message) + if corrupt: + mod_message = BAD_JSON_PREFIX + str_message + BAD_JSON_SUFFIX + else: + mod_message = str_message + fire_mqtt_message(self.hass, topic, mod_message) + self.hass.block_till_done() + + def assert_location_state(self, location): + """Test the assertion of a location state.""" + state = self.hass.states.get(DEVICE_TRACKER_STATE) + self.assertEqual(state.state, location) + + def assert_location_latitude(self, latitude): + """Test the assertion of a location latitude.""" + state = self.hass.states.get(DEVICE_TRACKER_STATE) + self.assertEqual(state.attributes.get('latitude'), latitude) + + def assert_location_longitude(self, longitude): + """Test the assertion of a location longitude.""" + state = self.hass.states.get(DEVICE_TRACKER_STATE) + self.assertEqual(state.attributes.get('longitude'), longitude) + + def assert_location_accuracy(self, accuracy): + """Test the assertion of a location accuracy.""" + state = self.hass.states.get(DEVICE_TRACKER_STATE) + self.assertEqual(state.attributes.get('gps_accuracy'), accuracy) + + +# pylint: disable=too-many-public-methods +class TestDeviceTrackerOwnTracks(BaseMQTT): """Test the OwnTrack sensor.""" - def setup_method(self, method): + # pylint: disable=invalid-name + + def setup_method(self, _): """Setup things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_mqtt_component(self.hass) - self.assertTrue(setup_component(self.hass, device_tracker.DOMAIN, { - device_tracker.DOMAIN: { - CONF_PLATFORM: 'owntracks', - CONF_MAX_GPS_ACCURACY: 200, - CONF_WAYPOINT_IMPORT: True, - CONF_WAYPOINT_WHITELIST: ['jon', 'greg'] - }})) + with assert_setup_component(1, device_tracker.DOMAIN): + assert setup_component(self.hass, device_tracker.DOMAIN, { + device_tracker.DOMAIN: { + CONF_PLATFORM: 'owntracks', + CONF_MAX_GPS_ACCURACY: 200, + CONF_WAYPOINT_IMPORT: True, + CONF_WAYPOINT_WHITELIST: ['jon', 'greg'] + }}) self.hass.states.set( 'zone.inner', 'zoning', @@ -254,7 +295,7 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase): owntracks.REGIONS_ENTERED = defaultdict(list) owntracks.MOBILE_BEACONS_ACTIVE = defaultdict(list) - def teardown_method(self, method): + def teardown_method(self, _): """Stop everything that was started.""" self.hass.stop() @@ -263,40 +304,6 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase): except FileNotFoundError: pass - def mock_see(**kwargs): - """Fake see method for owntracks.""" - return - - def send_message(self, topic, message, corrupt=False): - """Test the sending of a message.""" - str_message = json.dumps(message) - if corrupt: - mod_message = BAD_JSON_PREFIX + str_message + BAD_JSON_SUFFIX - else: - mod_message = str_message - fire_mqtt_message(self.hass, topic, mod_message) - self.hass.block_till_done() - - def assert_location_state(self, location): - """Test the assertion of a location state.""" - state = self.hass.states.get(DEVICE_TRACKER_STATE) - self.assertEqual(state.state, location) - - def assert_location_latitude(self, latitude): - """Test the assertion of a location latitude.""" - state = self.hass.states.get(DEVICE_TRACKER_STATE) - self.assertEqual(state.attributes.get('latitude'), latitude) - - def assert_location_longitude(self, longitude): - """Test the assertion of a location longitude.""" - state = self.hass.states.get(DEVICE_TRACKER_STATE) - self.assertEqual(state.attributes.get('longitude'), longitude) - - def assert_location_accuracy(self, accuracy): - """Test the assertion of a location accuracy.""" - state = self.hass.states.get(DEVICE_TRACKER_STATE) - self.assertEqual(state.attributes.get('gps_accuracy'), accuracy) - def assert_tracker_state(self, location): """Test the assertion of a tracker state.""" state = self.hass.states.get(REGION_TRACKER_STATE) @@ -312,7 +319,7 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase): state = self.hass.states.get(REGION_TRACKER_STATE) self.assertEqual(state.attributes.get('gps_accuracy'), accuracy) - def test_location_invalid_devid(self): + def test_location_invalid_devid(self): # pylint: disable=invalid-name """Test the update of a location.""" self.send_message('owntracks/paulus/nexus-5x', LOCATION_MESSAGE) @@ -588,7 +595,7 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase): exit_message = REGION_LEAVE_MESSAGE.copy() exit_message['desc'] = IBEACON_DEVICE - for i in range(0, 20): + for _ in range(0, 20): fire_mqtt_message( self.hass, EVENT_TOPIC, json.dumps(enter_message)) fire_mqtt_message( @@ -637,12 +644,16 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase): def test_waypoint_import_no_whitelist(self): """Test import of list of waypoints with no whitelist set.""" + def mock_see(**kwargs): + """Fake see method for owntracks.""" + return + test_config = { CONF_PLATFORM: 'owntracks', CONF_MAX_GPS_ACCURACY: 200, CONF_WAYPOINT_IMPORT: True } - owntracks.setup_scanner(self.hass, test_config, self.mock_see) + owntracks.setup_scanner(self.hass, test_config, mock_see) waypoints_message = WAYPOINTS_EXPORTED_MESSAGE.copy() self.send_message(WAYPOINT_TOPIC_BLOCKED, waypoints_message) # Check if it made it into states @@ -690,7 +701,18 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase): self.send_message(LOCATION_TOPIC, ENCRYPTED_LOCATION_MESSAGE) self.assert_location_latitude(2.0) - def mock_cipher(): + +class TestDeviceTrackerOwnTrackConfigs(BaseMQTT): + """Test the OwnTrack sensor.""" + + # pylint: disable=invalid-name + + def setup_method(self, method): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + mock_mqtt_component(self.hass) + + def mock_cipher(): # pylint: disable=no-method-argument """Return a dummy pickle-based cipher.""" def mock_decrypt(ciphertext, key): """Decrypt/unpickle.""" @@ -705,11 +727,12 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase): mock_cipher) def test_encrypted_payload(self): """Test encrypted payload.""" - self.assertTrue(device_tracker.setup(self.hass, { - device_tracker.DOMAIN: { - CONF_PLATFORM: 'owntracks', - CONF_SECRET: SECRET_KEY, - }})) + with assert_setup_component(1, device_tracker.DOMAIN): + assert setup_component(self.hass, device_tracker.DOMAIN, { + device_tracker.DOMAIN: { + CONF_PLATFORM: 'owntracks', + CONF_SECRET: SECRET_KEY, + }}) self.send_message(LOCATION_TOPIC, MOCK_ENCRYPTED_LOCATION_MESSAGE) self.assert_location_latitude(2.0) @@ -717,24 +740,26 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase): mock_cipher) def test_encrypted_payload_topic_key(self): """Test encrypted payload with a topic key.""" - self.assertTrue(device_tracker.setup(self.hass, { - device_tracker.DOMAIN: { - CONF_PLATFORM: 'owntracks', - CONF_SECRET: { - LOCATION_TOPIC: SECRET_KEY, - }}})) + with assert_setup_component(1, device_tracker.DOMAIN): + assert setup_component(self.hass, device_tracker.DOMAIN, { + device_tracker.DOMAIN: { + CONF_PLATFORM: 'owntracks', + CONF_SECRET: { + LOCATION_TOPIC: SECRET_KEY, + }}}) self.send_message(LOCATION_TOPIC, MOCK_ENCRYPTED_LOCATION_MESSAGE) self.assert_location_latitude(2.0) @patch('homeassistant.components.device_tracker.owntracks.get_cipher', mock_cipher) def test_encrypted_payload_no_key(self): - """Test encrypted payload with no key.""" - self.assertTrue(device_tracker.setup(self.hass, { - device_tracker.DOMAIN: { - CONF_PLATFORM: 'owntracks', - # key missing - }})) + """Test encrypted payload with no key, .""" + with assert_setup_component(1, device_tracker.DOMAIN): + assert setup_component(self.hass, device_tracker.DOMAIN, { + device_tracker.DOMAIN: { + CONF_PLATFORM: 'owntracks', + # key missing + }}) self.send_message(LOCATION_TOPIC, MOCK_ENCRYPTED_LOCATION_MESSAGE) self.assert_location_latitude(None) @@ -742,11 +767,12 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase): mock_cipher) def test_encrypted_payload_wrong_key(self): """Test encrypted payload with wrong key.""" - self.assertTrue(device_tracker.setup(self.hass, { - device_tracker.DOMAIN: { - CONF_PLATFORM: 'owntracks', - CONF_SECRET: 'wrong key', - }})) + with assert_setup_component(1, device_tracker.DOMAIN): + assert setup_component(self.hass, device_tracker.DOMAIN, { + device_tracker.DOMAIN: { + CONF_PLATFORM: 'owntracks', + CONF_SECRET: 'wrong key', + }}) self.send_message(LOCATION_TOPIC, MOCK_ENCRYPTED_LOCATION_MESSAGE) self.assert_location_latitude(None) @@ -754,12 +780,13 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase): mock_cipher) def test_encrypted_payload_wrong_topic_key(self): """Test encrypted payload with wrong topic key.""" - self.assertTrue(device_tracker.setup(self.hass, { - device_tracker.DOMAIN: { - CONF_PLATFORM: 'owntracks', - CONF_SECRET: { - LOCATION_TOPIC: 'wrong key' - }}})) + with assert_setup_component(1, device_tracker.DOMAIN): + assert setup_component(self.hass, device_tracker.DOMAIN, { + device_tracker.DOMAIN: { + CONF_PLATFORM: 'owntracks', + CONF_SECRET: { + LOCATION_TOPIC: 'wrong key' + }}}) self.send_message(LOCATION_TOPIC, MOCK_ENCRYPTED_LOCATION_MESSAGE) self.assert_location_latitude(None) @@ -767,11 +794,12 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase): mock_cipher) def test_encrypted_payload_no_topic_key(self): """Test encrypted payload with no topic key.""" - self.assertTrue(device_tracker.setup(self.hass, { - device_tracker.DOMAIN: { - CONF_PLATFORM: 'owntracks', - CONF_SECRET: { - 'owntracks/{}/{}'.format(USER, 'otherdevice'): 'foobar' - }}})) + with assert_setup_component(1, device_tracker.DOMAIN): + assert setup_component(self.hass, device_tracker.DOMAIN, { + device_tracker.DOMAIN: { + CONF_PLATFORM: 'owntracks', + CONF_SECRET: { + 'owntracks/{}/{}'.format(USER, 'otherdevice'): 'foobar' + }}}) self.send_message(LOCATION_TOPIC, MOCK_ENCRYPTED_LOCATION_MESSAGE) self.assert_location_latitude(None)