diff --git a/homeassistant/components/media_player/universal.py b/homeassistant/components/media_player/universal.py index 09bb12ec332..359249f15e2 100644 --- a/homeassistant/components/media_player/universal.py +++ b/homeassistant/components/media_player/universal.py @@ -215,15 +215,6 @@ class UniversalMediaPlayer(MediaPlayerDevice): else: return None - def _cache_active_child_state(self): - """ The state of the active child or None """ - for child_name in self._children: - child_state = self.hass.states.get(child_name) - if child_state and child_state.state not in OFF_STATES: - self._child_state = child_state - return - self._child_state = None - @property def name(self): """ name of universal player """ diff --git a/tests/components/binary_sensor/test_command_sensor.py b/tests/components/binary_sensor/test_command_sensor.py new file mode 100644 index 00000000000..aa6a87c2061 --- /dev/null +++ b/tests/components/binary_sensor/test_command_sensor.py @@ -0,0 +1,78 @@ +""" +tests.components.binary_sensor.command_sensor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tests command binary sensor. +""" + +import unittest + +import homeassistant.core as ha +from homeassistant.const import (STATE_ON, STATE_OFF) +from homeassistant.components.binary_sensor import command_sensor + + +class TestCommandSensorBinarySensor(unittest.TestCase): + """ Test the Template sensor. """ + + def setUp(self): + self.hass = ha.HomeAssistant() + + def tearDown(self): + """ Stop down stuff we started. """ + self.hass.stop() + + def test_setup(self): + """ Test sensor setup """ + config = {'name': 'Test', + 'command': 'echo 1', + 'payload_on': '1', + 'payload_off': '0'} + devices = [] + + def add_dev_callback(devs): + """ callback to add device """ + for dev in devs: + devices.append(dev) + + command_sensor.setup_platform( + self.hass, config, add_dev_callback) + + self.assertEqual(1, len(devices)) + entity = devices[0] + self.assertEqual('Test', entity.name) + self.assertEqual(STATE_ON, entity.state) + + def test_setup_bad_config(self): + """ Test setup with a bad config """ + config = {} + + devices = [] + + def add_dev_callback(devs): + """ callback to add device """ + for dev in devs: + devices.append(dev) + + self.assertFalse(command_sensor.setup_platform( + self.hass, config, add_dev_callback)) + + self.assertEqual(0, len(devices)) + + def test_template(self): + """ Test command sensor with template """ + data = command_sensor.CommandSensorData('echo 10') + + entity = command_sensor.CommandBinarySensor( + self.hass, data, 'test', '1.0', '0', '{{ value | multiply(0.1) }}') + + self.assertEqual(STATE_ON, entity.state) + + def test_sensor_off(self): + """ Test command sensor with template """ + data = command_sensor.CommandSensorData('echo 0') + + entity = command_sensor.CommandBinarySensor( + self.hass, data, 'test', '1', '0', None) + + self.assertEqual(STATE_OFF, entity.state) diff --git a/tests/components/media_player/test_universal.py b/tests/components/media_player/test_universal.py index eca863b935e..e359700f2fa 100644 --- a/tests/components/media_player/test_universal.py +++ b/tests/components/media_player/test_universal.py @@ -14,6 +14,8 @@ import homeassistant.components.switch as switch import homeassistant.components.media_player as media_player import homeassistant.components.media_player.universal as universal +from tests.common import mock_service + class MockMediaPlayer(media_player.MediaPlayerDevice): """ Mock media player for testing """ @@ -28,6 +30,9 @@ class MockMediaPlayer(media_player.MediaPlayerDevice): self._media_title = None self._supported_media_commands = 0 + self.turn_off_service_calls = mock_service( + hass, media_player.DOMAIN, media_player.SERVICE_TURN_OFF) + @property def name(self): """ name of player """ @@ -135,6 +140,65 @@ class TestMediaPlayer(unittest.TestCase): self.assertTrue(response) self.assertEqual(config_start, self.config_children_and_attr) + def test_check_config_no_name(self): + """ Check config with no Name entry """ + response = universal.validate_config({'platform': 'universal'}) + + self.assertFalse(response) + + def test_check_config_bad_children(self): + """ Check config with bad children entry """ + config_no_children = {'name': 'test', 'platform': 'universal'} + config_bad_children = {'name': 'test', 'children': {}, + 'platform': 'universal'} + + response = universal.validate_config(config_no_children) + self.assertTrue(response) + self.assertEqual([], config_no_children['children']) + + response = universal.validate_config(config_bad_children) + self.assertTrue(response) + self.assertEqual([], config_bad_children['children']) + + def test_check_config_bad_commands(self): + """ Check config with bad commands entry """ + config = {'name': 'test', 'commands': [], 'platform': 'universal'} + + response = universal.validate_config(config) + self.assertTrue(response) + self.assertEqual({}, config['commands']) + + def test_check_config_bad_attributes(self): + """ Check config with bad attributes """ + config = {'name': 'test', 'attributes': [], 'platform': 'universal'} + + response = universal.validate_config(config) + self.assertTrue(response) + self.assertEqual({}, config['attributes']) + + def test_check_config_bad_key(self): + """ check config with bad key """ + config = {'name': 'test', 'asdf': 5, 'platform': 'universal'} + + response = universal.validate_config(config) + self.assertTrue(response) + self.assertFalse('asdf' in config) + + def test_platform_setup(self): + """ test platform setup """ + config = {'name': 'test', 'platform': 'universal'} + entities = [] + + def add_devices(new_entities): + """ add devices to list """ + for dev in new_entities: + entities.append(dev) + + universal.setup_platform(self.hass, config, add_devices) + + self.assertEqual(1, len(entities)) + self.assertEqual('test', entities[0].name) + def test_master_state(self): """ test master state property """ config = self.config_children_only @@ -230,20 +294,20 @@ class TestMediaPlayer(unittest.TestCase): ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) ump.update() - self.assertEqual(ump.state, STATE_OFF) + self.assertEqual(STATE_OFF, ump.state) self.hass.states.set(self.mock_state_switch_id, STATE_ON) ump.update() - self.assertEqual(ump.state, STATE_ON) + self.assertEqual(STATE_ON, ump.state) self.mock_mp_1._state = STATE_PLAYING self.mock_mp_1.update_ha_state() ump.update() - self.assertEqual(ump.state, STATE_PLAYING) + self.assertEqual(STATE_PLAYING, ump.state) self.hass.states.set(self.mock_state_switch_id, STATE_OFF) ump.update() - self.assertEqual(ump.state, STATE_OFF) + self.assertEqual(STATE_OFF, ump.state) def test_volume_level(self): """ test volume level property """ @@ -340,3 +404,38 @@ class TestMediaPlayer(unittest.TestCase): | universal.SUPPORT_VOLUME_STEP | universal.SUPPORT_VOLUME_MUTE self.assertEqual(check_flags, ump.supported_media_commands) + + def test_service_call_to_child(self): + """ test a service call that should be routed to a child """ + config = self.config_children_only + universal.validate_config(config) + + ump = universal.UniversalMediaPlayer(self.hass, **config) + ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) + ump.update() + + self.mock_mp_2._state = STATE_PLAYING + self.mock_mp_2.update_ha_state() + ump.update() + + ump.turn_off() + self.assertEqual(1, len(self.mock_mp_2.turn_off_service_calls)) + + def test_service_call_to_command(self): + config = self.config_children_only + config['commands'] = \ + {'turn_off': {'service': 'test.turn_off', 'data': {}}} + universal.validate_config(config) + + service = mock_service(self.hass, 'test', 'turn_off') + + ump = universal.UniversalMediaPlayer(self.hass, **config) + ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) + ump.update() + + self.mock_mp_2._state = STATE_PLAYING + self.mock_mp_2.update_ha_state() + ump.update() + + ump.turn_off() + self.assertEqual(1, len(service)) diff --git a/tests/components/sensor/test_command_sensor.py b/tests/components/sensor/test_command_sensor.py new file mode 100644 index 00000000000..ae6c9452d3f --- /dev/null +++ b/tests/components/sensor/test_command_sensor.py @@ -0,0 +1,75 @@ +""" +tests.components.sensor.command_sensor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tests command sensor. +""" + +import unittest + +import homeassistant.core as ha +from homeassistant.components.sensor import command_sensor + + +class TestCommandSensorSensor(unittest.TestCase): + """ Test the Template sensor. """ + + def setUp(self): + self.hass = ha.HomeAssistant() + + def tearDown(self): + """ Stop down stuff we started. """ + self.hass.stop() + + def test_setup(self): + """ Test sensor setup """ + config = {'name': 'Test', + 'unit_of_measurement': 'in', + 'command': 'echo 5'} + devices = [] + + def add_dev_callback(devs): + """ callback to add device """ + for dev in devs: + devices.append(dev) + + command_sensor.setup_platform( + self.hass, config, add_dev_callback) + + self.assertEqual(1, len(devices)) + entity = devices[0] + self.assertEqual('Test', entity.name) + self.assertEqual('in', entity.unit_of_measurement) + self.assertEqual('5', entity.state) + + def test_setup_bad_config(self): + """ Test setup with a bad config """ + config = {} + + devices = [] + + def add_dev_callback(devs): + """ callback to add device """ + for dev in devs: + devices.append(dev) + + self.assertFalse(command_sensor.setup_platform( + self.hass, config, add_dev_callback)) + + self.assertEqual(0, len(devices)) + + def test_template(self): + """ Test command sensor with template """ + data = command_sensor.CommandSensorData('echo 50') + + entity = command_sensor.CommandSensor( + self.hass, data, 'test', 'in', '{{ value | multiply(0.1) }}') + + self.assertEqual(5, float(entity.state)) + + def test_bad_command(self): + """ Test bad command """ + data = command_sensor.CommandSensorData('asdfasdf') + data.update() + + self.assertEqual(None, data.value) diff --git a/tests/components/test_introduction.py b/tests/components/test_introduction.py new file mode 100644 index 00000000000..42c16081d1e --- /dev/null +++ b/tests/components/test_introduction.py @@ -0,0 +1,28 @@ +""" +tests.components.introduction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Test introduction. + +This test is primarily to ensure that default components don't crash HASS. +""" + +import unittest + +import homeassistant.core as ha +from homeassistant.components import introduction + + +class TestIntroduction(unittest.TestCase): + """ Test Introduction. """ + + def setUp(self): + self.hass = ha.HomeAssistant() + + def tearDown(self): + """ Stop down stuff we started. """ + self.hass.stop() + + def test_setup(self): + """ Test Introduction setup """ + self.assertTrue(introduction.setup(self.hass, {})) diff --git a/tests/components/test_logger.py b/tests/components/test_logger.py new file mode 100644 index 00000000000..5e3aeda88d3 --- /dev/null +++ b/tests/components/test_logger.py @@ -0,0 +1,61 @@ +""" +tests.test_logger +~~~~~~~~~~~~~~~~~~ + +Tests logger component. +""" +from collections import namedtuple +import logging +import unittest + +from homeassistant.components import logger + +RECORD = namedtuple('record', ('name', 'levelno')) + + +class TestUpdater(unittest.TestCase): + """ Test logger component. """ + + def setUp(self): + """ Create default config """ + self.log_config = {'logger': + {'default': 'warning', 'logs': {'test': 'info'}}} + + def tearDown(self): + """ Reset logs """ + del logging.root.handlers[-1] + + def test_logger_setup(self): + """ Uses logger to create a logging filter """ + logger.setup(None, self.log_config) + + self.assertTrue(len(logging.root.handlers) > 0) + handler = logging.root.handlers[-1] + + self.assertEqual(len(handler.filters), 1) + log_filter = handler.filters[0].logfilter + + self.assertEqual(log_filter['default'], logging.WARNING) + self.assertEqual(log_filter['logs']['test'], logging.INFO) + + def test_logger_test_filters(self): + """ Tests resulting filter operation """ + logger.setup(None, self.log_config) + + log_filter = logging.root.handlers[-1].filters[0] + + # blocked default record + record = RECORD('asdf', logging.DEBUG) + self.assertFalse(log_filter.filter(record)) + + # allowed default record + record = RECORD('asdf', logging.WARNING) + self.assertTrue(log_filter.filter(record)) + + # blocked named record + record = RECORD('test', logging.DEBUG) + self.assertFalse(log_filter.filter(record)) + + # allowed named record + record = RECORD('test', logging.INFO) + self.assertTrue(log_filter.filter(record)) diff --git a/tests/resources/pyhelloworld3.zip b/tests/resources/pyhelloworld3.zip new file mode 100644 index 00000000000..f2a419e9f34 Binary files /dev/null and b/tests/resources/pyhelloworld3.zip differ diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index a0c4da894f0..688e5fb0b41 100644 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -11,8 +11,10 @@ import unittest from unittest import mock from homeassistant import core, bootstrap -from homeassistant.const import __version__ +from homeassistant.const import (__version__, CONF_LATITUDE, CONF_LONGITUDE, + CONF_NAME, CONF_CUSTOMIZE) import homeassistant.util.dt as dt_util +from homeassistant.helpers.entity import Entity from tests.common import mock_detect_location_info @@ -83,3 +85,23 @@ class TestBootstrap(unittest.TestCase): bootstrap.process_ha_config_upgrade(hass) self.assertTrue(os.path.isfile(check_file)) + + def test_entity_customization(self): + """ Test entity customization through config """ + config = {CONF_LATITUDE: 50, + CONF_LONGITUDE: 50, + CONF_NAME: 'Test', + CONF_CUSTOMIZE: {'test.test': {'hidden': True}}} + + hass = core.HomeAssistant() + + bootstrap.process_ha_core_config(hass, config) + + entity = Entity() + entity.entity_id = 'test.test' + entity.hass = hass + entity.update_ha_state() + + state = hass.states.get('test.test') + + self.assertTrue(state.attributes['hidden']) diff --git a/tests/util/test_package.py b/tests/util/test_package.py new file mode 100644 index 00000000000..db5a8a88e94 --- /dev/null +++ b/tests/util/test_package.py @@ -0,0 +1,61 @@ +""" +Tests Home Assistant package util methods. +""" +import os +import tempfile +import unittest + +import homeassistant.bootstrap as bootstrap +import homeassistant.util.package as package + +RESOURCE_DIR = os.path.abspath( + os.path.join(os.path.dirname(__file__), '..', 'resources')) + +TEST_EXIST_REQ = "pip>=7.0.0" +TEST_NEW_REQ = "pyhelloworld3==1.0.0" +TEST_ZIP_REQ = 'file://{}#{}' \ + .format(os.path.join(RESOURCE_DIR, 'pyhelloworld3.zip'), TEST_NEW_REQ) + + +class TestPackageUtil(unittest.TestCase): + """ Tests for homeassistant.util.package module """ + + def setUp(self): + """ Create local library for testing """ + self.tmp_dir = tempfile.TemporaryDirectory() + self.lib_dir = os.path.join(self.tmp_dir.name, 'lib') + + def tearDown(self): + """ Remove local library """ + self.tmp_dir.cleanup() + + def test_install_existing_package(self): + """ Test an install attempt on an existing package """ + self.assertTrue(package.check_package_exists( + TEST_EXIST_REQ, self.lib_dir)) + + self.assertTrue(package.install_package(TEST_EXIST_REQ)) + + def test_install_package_zip(self): + """ Test an install attempt from a zip path """ + self.assertFalse(package.check_package_exists( + TEST_ZIP_REQ, self.lib_dir)) + self.assertFalse(package.check_package_exists( + TEST_NEW_REQ, self.lib_dir)) + + self.assertTrue(package.install_package( + TEST_ZIP_REQ, True, self.lib_dir)) + + self.assertTrue(package.check_package_exists( + TEST_ZIP_REQ, self.lib_dir)) + self.assertTrue(package.check_package_exists( + TEST_NEW_REQ, self.lib_dir)) + + bootstrap.mount_local_lib_path(self.tmp_dir.name) + + try: + import pyhelloworld3 + except ImportError: + self.fail('Unable to import pyhelloworld3 after installing it.') + + self.assertEqual(pyhelloworld3.__version__, '1.0.0')