mirror of
https://github.com/home-assistant/core.git
synced 2025-12-24 12:59:34 +00:00
Device tracker component & platform validation. No more home_range. (#2908)
* Device tracker component & platform validation. No more home_range. * Mock, bluetooth * Renamed _CONFIG_SCHEMA. Raise warning for #1606 * test duplicates * Fix assert * Coverage * Typing * T fixes
This commit is contained in:
committed by
Teagan Glenn
parent
16e0187fcc
commit
55d305359e
@@ -1,10 +1,10 @@
|
||||
"""The tests for the device tracker component."""
|
||||
# pylint: disable=protected-access,too-many-public-methods
|
||||
import logging
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
from datetime import datetime, timedelta
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from homeassistant.loader import get_component
|
||||
import homeassistant.util.dt as dt_util
|
||||
@@ -12,13 +12,21 @@ from homeassistant.const import (
|
||||
ATTR_ENTITY_ID, ATTR_ENTITY_PICTURE, ATTR_FRIENDLY_NAME, ATTR_HIDDEN,
|
||||
STATE_HOME, STATE_NOT_HOME, CONF_PLATFORM)
|
||||
import homeassistant.components.device_tracker as device_tracker
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
from tests.common import (
|
||||
get_test_home_assistant, fire_time_changed, fire_service_discovered)
|
||||
get_test_home_assistant, fire_time_changed, fire_service_discovered,
|
||||
patch_yaml_files)
|
||||
|
||||
TEST_PLATFORM = {device_tracker.DOMAIN: {CONF_PLATFORM: 'test'}}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
"""Test the Device tracker."""
|
||||
hass = None # HomeAssistant
|
||||
yaml_devices = None # type: str
|
||||
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Setup things to be run when tests are started."""
|
||||
@@ -48,27 +56,28 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
|
||||
def test_reading_broken_yaml_config(self): # pylint: disable=no-self-use
|
||||
"""Test when known devices contains invalid data."""
|
||||
with tempfile.NamedTemporaryFile() as fpt:
|
||||
# file is empty
|
||||
assert device_tracker.load_config(fpt.name, None, False, 0) == []
|
||||
|
||||
fpt.write('100'.encode('utf-8'))
|
||||
fpt.flush()
|
||||
|
||||
# file contains a non-dict format
|
||||
assert device_tracker.load_config(fpt.name, None, False, 0) == []
|
||||
files = {'empty.yaml': '',
|
||||
'bad.yaml': '100',
|
||||
'ok.yaml': 'my_device:\n name: Device'}
|
||||
with patch_yaml_files(files):
|
||||
# File is empty
|
||||
assert device_tracker.load_config('empty.yaml', None, False) == []
|
||||
# File contains a non-dict format
|
||||
assert device_tracker.load_config('bad.yaml', None, False) == []
|
||||
# A file that works fine
|
||||
assert len(device_tracker.load_config('ok.yaml', None, False)) == 1
|
||||
|
||||
def test_reading_yaml_config(self):
|
||||
"""Test the rendering of the YAML configuration."""
|
||||
dev_id = 'test'
|
||||
device = device_tracker.Device(
|
||||
self.hass, timedelta(seconds=180), 0, True, dev_id,
|
||||
self.hass, timedelta(seconds=180), True, dev_id,
|
||||
'AB:CD:EF:GH:IJ', 'Test name', picture='http://test.picture',
|
||||
away_hide=True)
|
||||
device_tracker.update_config(self.yaml_devices, dev_id, device)
|
||||
self.assertTrue(device_tracker.setup(self.hass, {}))
|
||||
self.assertTrue(device_tracker.setup(self.hass, TEST_PLATFORM))
|
||||
config = device_tracker.load_config(self.yaml_devices, self.hass,
|
||||
device.consider_home, 0)[0]
|
||||
device.consider_home)[0]
|
||||
self.assertEqual(device.dev_id, config.dev_id)
|
||||
self.assertEqual(device.track, config.track)
|
||||
self.assertEqual(device.mac, config.mac)
|
||||
@@ -76,12 +85,45 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
self.assertEqual(device.away_hide, config.away_hide)
|
||||
self.assertEqual(device.consider_home, config.consider_home)
|
||||
|
||||
@patch('homeassistant.components.device_tracker._LOGGER.warning')
|
||||
def test_track_with_duplicate_mac_dev_id(self, mock_warning): \
|
||||
# pylint: disable=invalid-name
|
||||
"""Test adding duplicate MACs or device IDs to DeviceTracker."""
|
||||
|
||||
devices = [
|
||||
device_tracker.Device(self.hass, True, True, 'my_device', 'AB:01',
|
||||
'My device', None, None, False),
|
||||
device_tracker.Device(self.hass, True, True, 'your_device',
|
||||
'AB:01', 'Your device', None, None, False)]
|
||||
device_tracker.DeviceTracker(self.hass, False, True, devices)
|
||||
_LOGGER.debug(mock_warning.call_args_list)
|
||||
assert mock_warning.call_count == 1, \
|
||||
"The only warning call should be duplicates (check DEBUG)"
|
||||
args, _ = mock_warning.call_args
|
||||
assert 'Duplicate device MAC' in args[0], \
|
||||
'Duplicate MAC warning expected'
|
||||
|
||||
mock_warning.reset_mock()
|
||||
devices = [
|
||||
device_tracker.Device(self.hass, True, True, 'my_device',
|
||||
'AB:01', 'My device', None, None, False),
|
||||
device_tracker.Device(self.hass, True, True, 'my_device',
|
||||
None, 'Your device', None, None, False)]
|
||||
device_tracker.DeviceTracker(self.hass, False, True, devices)
|
||||
|
||||
_LOGGER.debug(mock_warning.call_args_list)
|
||||
assert mock_warning.call_count == 1, \
|
||||
"The only warning call should be duplicates (check DEBUG)"
|
||||
args, _ = mock_warning.call_args
|
||||
assert 'Duplicate device IDs' in args[0], \
|
||||
'Duplicate device IDs warning expected'
|
||||
|
||||
def test_setup_without_yaml_file(self):
|
||||
"""Test with no YAML file."""
|
||||
self.assertTrue(device_tracker.setup(self.hass, {}))
|
||||
self.assertTrue(device_tracker.setup(self.hass, TEST_PLATFORM))
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def test_adding_unknown_device_to_config(self):
|
||||
def test_adding_unknown_device_to_config(self): \
|
||||
# pylint: disable=invalid-name
|
||||
"""Test the adding of unknown devices to configuration file."""
|
||||
scanner = get_component('device_tracker.test').SCANNER
|
||||
scanner.reset()
|
||||
@@ -90,7 +132,7 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
self.assertTrue(device_tracker.setup(self.hass, {
|
||||
device_tracker.DOMAIN: {CONF_PLATFORM: 'test'}}))
|
||||
config = device_tracker.load_config(self.yaml_devices, self.hass,
|
||||
timedelta(seconds=0), 0)
|
||||
timedelta(seconds=0))
|
||||
assert len(config) == 1
|
||||
assert config[0].dev_id == 'dev1'
|
||||
assert config[0].track
|
||||
@@ -99,7 +141,7 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
"""Test the Gravatar generation."""
|
||||
dev_id = 'test'
|
||||
device = device_tracker.Device(
|
||||
self.hass, timedelta(seconds=180), 0, True, dev_id,
|
||||
self.hass, timedelta(seconds=180), True, dev_id,
|
||||
'AB:CD:EF:GH:IJ', 'Test name', gravatar='test@example.com')
|
||||
gravatar_url = ("https://www.gravatar.com/avatar/"
|
||||
"55502f40dc8b7c769880b10874abc9d0.jpg?s=80&d=wavatar")
|
||||
@@ -109,7 +151,7 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
"""Test that Gravatar overrides picture."""
|
||||
dev_id = 'test'
|
||||
device = device_tracker.Device(
|
||||
self.hass, timedelta(seconds=180), 0, True, dev_id,
|
||||
self.hass, timedelta(seconds=180), True, dev_id,
|
||||
'AB:CD:EF:GH:IJ', 'Test name', picture='http://test.picture',
|
||||
gravatar='test@example.com')
|
||||
gravatar_url = ("https://www.gravatar.com/avatar/"
|
||||
@@ -122,8 +164,8 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
|
||||
with patch.dict(device_tracker.DISCOVERY_PLATFORMS, {'test': 'test'}):
|
||||
with patch.object(scanner, 'scan_devices') as mock_scan:
|
||||
self.assertTrue(device_tracker.setup(self.hass, {
|
||||
device_tracker.DOMAIN: {CONF_PLATFORM: 'test'}}))
|
||||
self.assertTrue(device_tracker.setup(self.hass,
|
||||
TEST_PLATFORM))
|
||||
fire_service_discovered(self.hass, 'test', {})
|
||||
self.assertTrue(mock_scan.called)
|
||||
|
||||
@@ -139,9 +181,9 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
with patch('homeassistant.components.device_tracker.dt_util.utcnow',
|
||||
return_value=register_time):
|
||||
self.assertTrue(device_tracker.setup(self.hass, {
|
||||
'device_tracker': {
|
||||
'platform': 'test',
|
||||
'consider_home': 59,
|
||||
device_tracker.DOMAIN: {
|
||||
CONF_PLATFORM: 'test',
|
||||
device_tracker.CONF_CONSIDER_HOME: 59,
|
||||
}}))
|
||||
|
||||
self.assertEqual(STATE_HOME,
|
||||
@@ -165,11 +207,11 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
picture = 'http://placehold.it/200x200'
|
||||
|
||||
device = device_tracker.Device(
|
||||
self.hass, timedelta(seconds=180), 0, True, dev_id, None,
|
||||
self.hass, timedelta(seconds=180), True, dev_id, None,
|
||||
friendly_name, picture, away_hide=True)
|
||||
device_tracker.update_config(self.yaml_devices, dev_id, device)
|
||||
|
||||
self.assertTrue(device_tracker.setup(self.hass, {}))
|
||||
self.assertTrue(device_tracker.setup(self.hass, TEST_PLATFORM))
|
||||
|
||||
attrs = self.hass.states.get(entity_id).attributes
|
||||
|
||||
@@ -181,15 +223,14 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
dev_id = 'test_entity'
|
||||
entity_id = device_tracker.ENTITY_ID_FORMAT.format(dev_id)
|
||||
device = device_tracker.Device(
|
||||
self.hass, timedelta(seconds=180), 0, True, dev_id, None,
|
||||
self.hass, timedelta(seconds=180), True, dev_id, None,
|
||||
away_hide=True)
|
||||
device_tracker.update_config(self.yaml_devices, dev_id, device)
|
||||
|
||||
scanner = get_component('device_tracker.test').SCANNER
|
||||
scanner.reset()
|
||||
|
||||
self.assertTrue(device_tracker.setup(self.hass, {
|
||||
device_tracker.DOMAIN: {CONF_PLATFORM: 'test'}}))
|
||||
self.assertTrue(device_tracker.setup(self.hass, TEST_PLATFORM))
|
||||
|
||||
self.assertTrue(self.hass.states.get(entity_id)
|
||||
.attributes.get(ATTR_HIDDEN))
|
||||
@@ -199,15 +240,14 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
dev_id = 'test_entity'
|
||||
entity_id = device_tracker.ENTITY_ID_FORMAT.format(dev_id)
|
||||
device = device_tracker.Device(
|
||||
self.hass, timedelta(seconds=180), 0, True, dev_id, None,
|
||||
self.hass, timedelta(seconds=180), True, dev_id, None,
|
||||
away_hide=True)
|
||||
device_tracker.update_config(self.yaml_devices, dev_id, device)
|
||||
|
||||
scanner = get_component('device_tracker.test').SCANNER
|
||||
scanner.reset()
|
||||
|
||||
self.assertTrue(device_tracker.setup(self.hass, {
|
||||
device_tracker.DOMAIN: {CONF_PLATFORM: 'test'}}))
|
||||
self.assertTrue(device_tracker.setup(self.hass, TEST_PLATFORM))
|
||||
|
||||
state = self.hass.states.get(device_tracker.ENTITY_ID_ALL_DEVICES)
|
||||
self.assertIsNotNone(state)
|
||||
@@ -217,40 +257,31 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
|
||||
@patch('homeassistant.components.device_tracker.DeviceTracker.see')
|
||||
def test_see_service(self, mock_see):
|
||||
"""Test the see service."""
|
||||
self.assertTrue(device_tracker.setup(self.hass, {}))
|
||||
mac = 'AB:CD:EF:GH'
|
||||
dev_id = 'some_device'
|
||||
host_name = 'example.com'
|
||||
location_name = 'Work'
|
||||
gps = [.3, .8]
|
||||
|
||||
device_tracker.see(self.hass, mac, dev_id, host_name, location_name,
|
||||
gps)
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
mock_see.assert_called_once_with(
|
||||
mac=mac, dev_id=dev_id, host_name=host_name,
|
||||
location_name=location_name, gps=gps)
|
||||
|
||||
@patch('homeassistant.components.device_tracker.DeviceTracker.see')
|
||||
def test_see_service_unicode_dev_id(self, mock_see):
|
||||
"""Test the see service with a unicode dev_id and NO MAC."""
|
||||
self.assertTrue(device_tracker.setup(self.hass, {}))
|
||||
self.assertTrue(device_tracker.setup(self.hass, TEST_PLATFORM))
|
||||
params = {
|
||||
'dev_id': chr(233), # e' acute accent from icloud
|
||||
'dev_id': 'some_device',
|
||||
'host_name': 'example.com',
|
||||
'location_name': 'Work',
|
||||
'gps': [.3, .8]
|
||||
}
|
||||
device_tracker.see(self.hass, **params)
|
||||
self.hass.pool.block_till_done()
|
||||
assert mock_see.call_count == 1
|
||||
mock_see.assert_called_once_with(**params)
|
||||
|
||||
def test_not_write_duplicate_yaml_keys(self):
|
||||
mock_see.reset_mock()
|
||||
params['dev_id'] += chr(233) # e' acute accent from icloud
|
||||
|
||||
device_tracker.see(self.hass, **params)
|
||||
self.hass.pool.block_till_done()
|
||||
assert mock_see.call_count == 1
|
||||
mock_see.assert_called_once_with(**params)
|
||||
|
||||
def test_not_write_duplicate_yaml_keys(self): \
|
||||
# pylint: disable=invalid-name
|
||||
"""Test that the device tracker will not generate invalid YAML."""
|
||||
self.assertTrue(device_tracker.setup(self.hass, {}))
|
||||
self.assertTrue(device_tracker.setup(self.hass, TEST_PLATFORM))
|
||||
|
||||
device_tracker.see(self.hass, 'mac_1', host_name='hello')
|
||||
device_tracker.see(self.hass, 'mac_2', host_name='hello')
|
||||
@@ -258,15 +289,46 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
config = device_tracker.load_config(self.yaml_devices, self.hass,
|
||||
timedelta(seconds=0), 0)
|
||||
timedelta(seconds=0))
|
||||
assert len(config) == 2
|
||||
|
||||
def test_not_allow_invalid_dev_id(self):
|
||||
def test_not_allow_invalid_dev_id(self): # pylint: disable=invalid-name
|
||||
"""Test that the device tracker will not allow invalid dev ids."""
|
||||
self.assertTrue(device_tracker.setup(self.hass, {}))
|
||||
self.assertTrue(device_tracker.setup(self.hass, TEST_PLATFORM))
|
||||
|
||||
device_tracker.see(self.hass, dev_id='hello-world')
|
||||
|
||||
config = device_tracker.load_config(self.yaml_devices, self.hass,
|
||||
timedelta(seconds=0), 0)
|
||||
timedelta(seconds=0))
|
||||
assert len(config) == 0
|
||||
|
||||
@patch('homeassistant.components.device_tracker._LOGGER.warning')
|
||||
def test_see_failures(self, mock_warning):
|
||||
"""Test that the device tracker see failures."""
|
||||
tracker = device_tracker.DeviceTracker(
|
||||
self.hass, timedelta(seconds=60), 0, [])
|
||||
|
||||
# MAC is not a string (but added)
|
||||
tracker.see(mac=567, host_name="Number MAC")
|
||||
|
||||
# No device id or MAC(not added)
|
||||
with self.assertRaises(HomeAssistantError):
|
||||
tracker.see()
|
||||
assert mock_warning.call_count == 0
|
||||
|
||||
# Ignore gps on invalid GPS (both added & warnings)
|
||||
tracker.see(mac='mac_1_bad_gps', gps=1)
|
||||
tracker.see(mac='mac_2_bad_gps', gps=[1])
|
||||
tracker.see(mac='mac_3_bad_gps', gps='gps')
|
||||
config = device_tracker.load_config(self.yaml_devices, self.hass,
|
||||
timedelta(seconds=0))
|
||||
assert mock_warning.call_count == 3
|
||||
|
||||
assert len(config) == 4
|
||||
|
||||
@patch('homeassistant.components.device_tracker.log_exception')
|
||||
def test_config_failure(self, mock_ex):
|
||||
"""Test that the device tracker see failures."""
|
||||
device_tracker.setup(self.hass, {device_tracker.DOMAIN: {
|
||||
device_tracker.CONF_CONSIDER_HOME: -1}})
|
||||
assert mock_ex.call_count == 1
|
||||
|
||||
Reference in New Issue
Block a user