From 2a6c0cfc172eefe0c742d7adf25f8bc4bb811390 Mon Sep 17 00:00:00 2001 From: Jon Caruana <jon@joncaruana.com> Date: Thu, 24 Nov 2016 09:52:15 -0800 Subject: [PATCH] LiteJet: Unit tests and new trigger options held_more_than and held_less_than. (#4473) * LiteJet: Unit tests and new trigger options held_more_than and held_less_than. * Unit tests for the LiteJet component and associated platforms. Coverage is almost 100% -- just misses one line. * The automation LiteJet trigger returns an empty "removal" function to ensure the automation base is happy with it. The pylitejet library doesn't actually support a real removal. * The automation LiteJet trigger can detect hold time and act appropriately to support things like short tap or long hold. * LiteJet: Fix indent in unit test source code. * LiteJet: Fix test_include_switches_* unit tests on Python 3.5 * LiteJet: Remove wait for state existence from unit tests. Recent fixes to discovery make this no longer necessary. --- .coveragerc | 3 - .../components/automation/litejet.py | 63 ++++- tests/components/automation/test_litejet.py | 251 ++++++++++++++++++ tests/components/light/test_litejet.py | 168 ++++++++++++ tests/components/scene/test_litejet.py | 64 +++++ tests/components/switch/test_litejet.py | 142 ++++++++++ tests/components/test_litejet.py | 42 +++ 7 files changed, 727 insertions(+), 6 deletions(-) create mode 100644 tests/components/automation/test_litejet.py create mode 100644 tests/components/light/test_litejet.py create mode 100644 tests/components/scene/test_litejet.py create mode 100644 tests/components/switch/test_litejet.py create mode 100644 tests/components/test_litejet.py diff --git a/.coveragerc b/.coveragerc index 7b7b063edb0..b34811a6173 100644 --- a/.coveragerc +++ b/.coveragerc @@ -40,9 +40,6 @@ omit = homeassistant/components/isy994.py homeassistant/components/*/isy994.py - homeassistant/components/litejet.py - homeassistant/components/*/litejet.py - homeassistant/components/modbus.py homeassistant/components/*/modbus.py diff --git a/homeassistant/components/automation/litejet.py b/homeassistant/components/automation/litejet.py index 875a24540ee..2b298d4979b 100644 --- a/homeassistant/components/automation/litejet.py +++ b/homeassistant/components/automation/litejet.py @@ -11,22 +11,34 @@ import voluptuous as vol from homeassistant.core import callback from homeassistant.const import CONF_PLATFORM import homeassistant.helpers.config_validation as cv +import homeassistant.util.dt as dt_util +from homeassistant.helpers.event import track_point_in_utc_time DEPENDENCIES = ['litejet'] _LOGGER = logging.getLogger(__name__) CONF_NUMBER = 'number' +CONF_HELD_MORE_THAN = 'held_more_than' +CONF_HELD_LESS_THAN = 'held_less_than' TRIGGER_SCHEMA = vol.Schema({ vol.Required(CONF_PLATFORM): 'litejet', - vol.Required(CONF_NUMBER): cv.positive_int + vol.Required(CONF_NUMBER): cv.positive_int, + vol.Optional(CONF_HELD_MORE_THAN): + vol.All(cv.time_period, cv.positive_timedelta), + vol.Optional(CONF_HELD_LESS_THAN): + vol.All(cv.time_period, cv.positive_timedelta) }) def async_trigger(hass, config, action): """Listen for events based on configuration.""" number = config.get(CONF_NUMBER) + held_more_than = config.get(CONF_HELD_MORE_THAN) + held_less_than = config.get(CONF_HELD_LESS_THAN) + pressed_time = None + cancel_pressed_more_than = None @callback def call_action(): @@ -34,8 +46,53 @@ def async_trigger(hass, config, action): hass.async_run_job(action, { 'trigger': { CONF_PLATFORM: 'litejet', - CONF_NUMBER: number + CONF_NUMBER: number, + CONF_HELD_MORE_THAN: held_more_than, + CONF_HELD_LESS_THAN: held_less_than }, }) - hass.data['litejet_system'].on_switch_released(number, call_action) + # held_more_than and held_less_than: trigger on released (if in time range) + # held_more_than: trigger after pressed with calculation + # held_less_than: trigger on released with calculation + # neither: trigger on pressed + + @callback + def pressed_more_than_satisfied(now): + """Handle the LiteJet's switch's button pressed >= held_more_than.""" + call_action() + + def pressed(): + """Handle the press of the LiteJet switch's button.""" + nonlocal cancel_pressed_more_than, pressed_time + nonlocal held_less_than, held_more_than + pressed_time = dt_util.utcnow() + if held_more_than is None and held_less_than is None: + call_action() + if held_more_than is not None and held_less_than is None: + cancel_pressed_more_than = track_point_in_utc_time( + hass, + pressed_more_than_satisfied, + dt_util.utcnow() + held_more_than) + + def released(): + """Handle the release of the LiteJet switch's button.""" + nonlocal cancel_pressed_more_than, pressed_time + nonlocal held_less_than, held_more_than + # pylint: disable=not-callable + if cancel_pressed_more_than is not None: + cancel_pressed_more_than() + cancel_pressed_more_than = None + held_time = dt_util.utcnow() - pressed_time + if held_less_than is not None and held_time < held_less_than: + if held_more_than is None or held_time > held_more_than: + call_action() + + hass.data['litejet_system'].on_switch_pressed(number, pressed) + hass.data['litejet_system'].on_switch_released(number, released) + + def async_remove(): + """Remove all subscriptions used for this trigger.""" + return + + return async_remove diff --git a/tests/components/automation/test_litejet.py b/tests/components/automation/test_litejet.py new file mode 100644 index 00000000000..be329487406 --- /dev/null +++ b/tests/components/automation/test_litejet.py @@ -0,0 +1,251 @@ +"""The tests for the litejet component.""" +import logging +import unittest +from unittest import mock +from datetime import timedelta + +from homeassistant import bootstrap +import homeassistant.util.dt as dt_util +from homeassistant.components import litejet +from tests.common import (fire_time_changed, get_test_home_assistant) +import homeassistant.components.automation as automation + +_LOGGER = logging.getLogger(__name__) + +ENTITY_SWITCH = 'switch.mock_switch_1' +ENTITY_SWITCH_NUMBER = 1 +ENTITY_OTHER_SWITCH = 'switch.mock_switch_2' +ENTITY_OTHER_SWITCH_NUMBER = 2 + + +class TestLiteJetTrigger(unittest.TestCase): + """Test the litejet component.""" + + @mock.patch('pylitejet.LiteJet') + def setup_method(self, method, mock_pylitejet): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + self.hass.start() + + self.switch_pressed_callbacks = {} + self.switch_released_callbacks = {} + self.calls = [] + + def get_switch_name(number): + return "Mock Switch #"+str(number) + + def on_switch_pressed(number, callback): + self.switch_pressed_callbacks[number] = callback + + def on_switch_released(number, callback): + self.switch_released_callbacks[number] = callback + + def record_call(service): + self.calls.append(service) + + self.mock_lj = mock_pylitejet.return_value + self.mock_lj.loads.return_value = range(0) + self.mock_lj.button_switches.return_value = range(1, 3) + self.mock_lj.all_switches.return_value = range(1, 6) + self.mock_lj.scenes.return_value = range(0) + self.mock_lj.get_switch_name.side_effect = get_switch_name + self.mock_lj.on_switch_pressed.side_effect = on_switch_pressed + self.mock_lj.on_switch_released.side_effect = on_switch_released + + config = { + 'litejet': { + 'port': '/tmp/this_will_be_mocked' + } + } + assert bootstrap.setup_component(self.hass, litejet.DOMAIN, config) + + self.hass.services.register('test', 'automation', record_call) + + self.hass.block_till_done() + + self.start_time = dt_util.utcnow() + self.last_delta = timedelta(0) + + def teardown_method(self, method): + """Stop everything that was started.""" + self.hass.stop() + + def simulate_press(self, number): + _LOGGER.info('*** simulate press of %d', number) + callback = self.switch_pressed_callbacks.get(number) + with mock.patch('homeassistant.helpers.condition.dt_util.utcnow', + return_value=self.start_time + self.last_delta): + if callback is not None: + callback() + self.hass.block_till_done() + + def simulate_release(self, number): + _LOGGER.info('*** simulate release of %d', number) + callback = self.switch_released_callbacks.get(number) + with mock.patch('homeassistant.helpers.condition.dt_util.utcnow', + return_value=self.start_time + self.last_delta): + if callback is not None: + callback() + self.hass.block_till_done() + + def simulate_time(self, delta): + _LOGGER.info( + '*** simulate time change by %s: %s', + delta, + self.start_time + delta) + self.last_delta = delta + with mock.patch('homeassistant.helpers.condition.dt_util.utcnow', + return_value=self.start_time + delta): + _LOGGER.info('now=%s', dt_util.utcnow()) + fire_time_changed(self.hass, self.start_time + delta) + self.hass.block_till_done() + _LOGGER.info('done with now=%s', dt_util.utcnow()) + + def setup_automation(self, trigger): + assert bootstrap.setup_component(self.hass, automation.DOMAIN, { + automation.DOMAIN: [ + { + 'alias': 'My Test', + 'trigger': trigger, + 'action': { + 'service': 'test.automation' + } + } + ] + }) + self.hass.block_till_done() + + def test_simple(self): + """Test the simplest form of a LiteJet trigger.""" + self.setup_automation({ + 'platform': 'litejet', + 'number': ENTITY_OTHER_SWITCH_NUMBER + }) + + self.simulate_press(ENTITY_OTHER_SWITCH_NUMBER) + self.simulate_release(ENTITY_OTHER_SWITCH_NUMBER) + + assert len(self.calls) == 1 + + def test_held_more_than_short(self): + """Test a too short hold.""" + self.setup_automation({ + 'platform': 'litejet', + 'number': ENTITY_OTHER_SWITCH_NUMBER, + 'held_more_than': { + 'milliseconds': '200' + } + }) + + self.simulate_press(ENTITY_OTHER_SWITCH_NUMBER) + self.simulate_time(timedelta(seconds=0.1)) + self.simulate_release(ENTITY_OTHER_SWITCH_NUMBER) + assert len(self.calls) == 0 + + def test_held_more_than_long(self): + """Test a hold that is long enough.""" + self.setup_automation({ + 'platform': 'litejet', + 'number': ENTITY_OTHER_SWITCH_NUMBER, + 'held_more_than': { + 'milliseconds': '200' + } + }) + + self.simulate_press(ENTITY_OTHER_SWITCH_NUMBER) + assert len(self.calls) == 0 + self.simulate_time(timedelta(seconds=0.3)) + assert len(self.calls) == 1 + self.simulate_release(ENTITY_OTHER_SWITCH_NUMBER) + assert len(self.calls) == 1 + + def test_held_less_than_short(self): + """Test a hold that is short enough.""" + self.setup_automation({ + 'platform': 'litejet', + 'number': ENTITY_OTHER_SWITCH_NUMBER, + 'held_less_than': { + 'milliseconds': '200' + } + }) + + self.simulate_press(ENTITY_OTHER_SWITCH_NUMBER) + self.simulate_time(timedelta(seconds=0.1)) + assert len(self.calls) == 0 + self.simulate_release(ENTITY_OTHER_SWITCH_NUMBER) + assert len(self.calls) == 1 + + def test_held_less_than_long(self): + """Test a hold that is too long.""" + self.setup_automation({ + 'platform': 'litejet', + 'number': ENTITY_OTHER_SWITCH_NUMBER, + 'held_less_than': { + 'milliseconds': '200' + } + }) + + self.simulate_press(ENTITY_OTHER_SWITCH_NUMBER) + assert len(self.calls) == 0 + self.simulate_time(timedelta(seconds=0.3)) + assert len(self.calls) == 0 + self.simulate_release(ENTITY_OTHER_SWITCH_NUMBER) + assert len(self.calls) == 0 + + def test_held_in_range_short(self): + """Test an in-range trigger with a too short hold.""" + self.setup_automation({ + 'platform': 'litejet', + 'number': ENTITY_OTHER_SWITCH_NUMBER, + 'held_more_than': { + 'milliseconds': '100' + }, + 'held_less_than': { + 'milliseconds': '300' + } + }) + + self.simulate_press(ENTITY_OTHER_SWITCH_NUMBER) + self.simulate_time(timedelta(seconds=0.05)) + self.simulate_release(ENTITY_OTHER_SWITCH_NUMBER) + assert len(self.calls) == 0 + + def test_held_in_range_just_right(self): + """Test an in-range trigger with a just right hold.""" + self.setup_automation({ + 'platform': 'litejet', + 'number': ENTITY_OTHER_SWITCH_NUMBER, + 'held_more_than': { + 'milliseconds': '100' + }, + 'held_less_than': { + 'milliseconds': '300' + } + }) + + self.simulate_press(ENTITY_OTHER_SWITCH_NUMBER) + assert len(self.calls) == 0 + self.simulate_time(timedelta(seconds=0.2)) + assert len(self.calls) == 0 + self.simulate_release(ENTITY_OTHER_SWITCH_NUMBER) + assert len(self.calls) == 1 + + def test_held_in_range_long(self): + """Test an in-range trigger with a too long hold.""" + self.setup_automation({ + 'platform': 'litejet', + 'number': ENTITY_OTHER_SWITCH_NUMBER, + 'held_more_than': { + 'milliseconds': '100' + }, + 'held_less_than': { + 'milliseconds': '300' + } + }) + + self.simulate_press(ENTITY_OTHER_SWITCH_NUMBER) + assert len(self.calls) == 0 + self.simulate_time(timedelta(seconds=0.4)) + assert len(self.calls) == 0 + self.simulate_release(ENTITY_OTHER_SWITCH_NUMBER) + assert len(self.calls) == 0 diff --git a/tests/components/light/test_litejet.py b/tests/components/light/test_litejet.py new file mode 100644 index 00000000000..ab10752b14a --- /dev/null +++ b/tests/components/light/test_litejet.py @@ -0,0 +1,168 @@ +"""The tests for the litejet component.""" +import logging +import unittest +from unittest import mock + +from homeassistant import bootstrap +from homeassistant.components import litejet +from tests.common import get_test_home_assistant +import homeassistant.components.light as light + +_LOGGER = logging.getLogger(__name__) + +ENTITY_LIGHT = 'light.mock_load_1' +ENTITY_LIGHT_NUMBER = 1 +ENTITY_OTHER_LIGHT = 'light.mock_load_2' +ENTITY_OTHER_LIGHT_NUMBER = 2 + + +class TestLiteJetLight(unittest.TestCase): + """Test the litejet component.""" + + @mock.patch('pylitejet.LiteJet') + def setup_method(self, method, mock_pylitejet): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + self.hass.start() + + self.load_activated_callbacks = {} + self.load_deactivated_callbacks = {} + + def get_load_name(number): + return "Mock Load #"+str(number) + + def on_load_activated(number, callback): + self.load_activated_callbacks[number] = callback + + def on_load_deactivated(number, callback): + self.load_deactivated_callbacks[number] = callback + + self.mock_lj = mock_pylitejet.return_value + self.mock_lj.loads.return_value = range(1, 3) + self.mock_lj.button_switches.return_value = range(0) + self.mock_lj.all_switches.return_value = range(0) + self.mock_lj.scenes.return_value = range(0) + self.mock_lj.get_load_level.return_value = 0 + self.mock_lj.get_load_name.side_effect = get_load_name + self.mock_lj.on_load_activated.side_effect = on_load_activated + self.mock_lj.on_load_deactivated.side_effect = on_load_deactivated + + assert bootstrap.setup_component( + self.hass, + litejet.DOMAIN, + { + 'litejet': { + 'port': '/tmp/this_will_be_mocked' + } + }) + self.hass.block_till_done() + + self.mock_lj.get_load_level.reset_mock() + + def light(self): + return self.hass.states.get(ENTITY_LIGHT) + + def other_light(self): + return self.hass.states.get(ENTITY_OTHER_LIGHT) + + def teardown_method(self, method): + """Stop everything that was started.""" + self.hass.stop() + + def test_on_brightness(self): + """Test turning the light on with brightness.""" + + assert self.light().state == 'off' + assert self.other_light().state == 'off' + + assert not light.is_on(self.hass, ENTITY_LIGHT) + + light.turn_on(self.hass, ENTITY_LIGHT, brightness=102) + self.hass.block_till_done() + self.mock_lj.activate_load_at.assert_called_with( + ENTITY_LIGHT_NUMBER, 39, 0) + + def test_on_off(self): + """Test turning the light on and off.""" + + assert self.light().state == 'off' + assert self.other_light().state == 'off' + + assert not light.is_on(self.hass, ENTITY_LIGHT) + + light.turn_on(self.hass, ENTITY_LIGHT) + self.hass.block_till_done() + self.mock_lj.activate_load.assert_called_with(ENTITY_LIGHT_NUMBER) + + light.turn_off(self.hass, ENTITY_LIGHT) + self.hass.block_till_done() + self.mock_lj.deactivate_load.assert_called_with(ENTITY_LIGHT_NUMBER) + + def test_activated_event(self): + """Test handling an event from LiteJet.""" + + self.mock_lj.get_load_level.return_value = 99 + + # Light 1 + + _LOGGER.info(self.load_activated_callbacks[ENTITY_LIGHT_NUMBER]) + self.load_activated_callbacks[ENTITY_LIGHT_NUMBER]() + self.hass.block_till_done() + + self.mock_lj.get_load_level.assert_called_once_with( + ENTITY_LIGHT_NUMBER) + + assert light.is_on(self.hass, ENTITY_LIGHT) + assert not light.is_on(self.hass, ENTITY_OTHER_LIGHT) + assert self.light().state == 'on' + assert self.other_light().state == 'off' + assert self.light().attributes.get(light.ATTR_BRIGHTNESS) == 255 + + # Light 2 + + self.mock_lj.get_load_level.return_value = 40 + + self.mock_lj.get_load_level.reset_mock() + + self.load_activated_callbacks[ENTITY_OTHER_LIGHT_NUMBER]() + self.hass.block_till_done() + + self.mock_lj.get_load_level.assert_called_once_with( + ENTITY_OTHER_LIGHT_NUMBER) + + assert light.is_on(self.hass, ENTITY_OTHER_LIGHT) + assert light.is_on(self.hass, ENTITY_LIGHT) + assert self.light().state == 'on' + assert self.other_light().state == 'on' + assert int(self.other_light().attributes[light.ATTR_BRIGHTNESS]) == 103 + + def test_deactivated_event(self): + """Test handling an event from LiteJet.""" + + # Initial state is on. + + self.mock_lj.get_load_level.return_value = 99 + + self.load_activated_callbacks[ENTITY_OTHER_LIGHT_NUMBER]() + self.hass.block_till_done() + + assert light.is_on(self.hass, ENTITY_OTHER_LIGHT) + + # Event indicates it is off now. + + self.mock_lj.get_load_level.reset_mock() + self.mock_lj.get_load_level.return_value = 0 + + self.load_deactivated_callbacks[ENTITY_OTHER_LIGHT_NUMBER]() + self.hass.block_till_done() + + # (Requesting the level is not strictly needed with a deactivated + # event but the implementation happens to do it. This could be + # changed to a assert_not_called in the future.) + self.mock_lj.get_load_level.assert_called_with( + ENTITY_OTHER_LIGHT_NUMBER) + + assert not light.is_on(self.hass, ENTITY_OTHER_LIGHT) + assert not light.is_on(self.hass, ENTITY_LIGHT) + assert self.light().state == 'off' + assert self.other_light().state == 'off' diff --git a/tests/components/scene/test_litejet.py b/tests/components/scene/test_litejet.py new file mode 100644 index 00000000000..7596736a567 --- /dev/null +++ b/tests/components/scene/test_litejet.py @@ -0,0 +1,64 @@ +"""The tests for the litejet component.""" +import logging +import unittest +from unittest import mock + +from homeassistant import bootstrap +from homeassistant.components import litejet +from tests.common import get_test_home_assistant +import homeassistant.components.scene as scene + +_LOGGER = logging.getLogger(__name__) + +ENTITY_SCENE = 'scene.mock_scene_1' +ENTITY_SCENE_NUMBER = 1 +ENTITY_OTHER_SCENE = 'scene.mock_scene_2' +ENTITY_OTHER_SCENE_NUMBER = 2 + + +class TestLiteJetScene(unittest.TestCase): + """Test the litejet component.""" + + @mock.patch('pylitejet.LiteJet') + def setup_method(self, method, mock_pylitejet): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + self.hass.start() + + def get_scene_name(number): + return "Mock Scene #"+str(number) + + self.mock_lj = mock_pylitejet.return_value + self.mock_lj.loads.return_value = range(0) + self.mock_lj.button_switches.return_value = range(0) + self.mock_lj.all_switches.return_value = range(0) + self.mock_lj.scenes.return_value = range(1, 3) + self.mock_lj.get_scene_name.side_effect = get_scene_name + + assert bootstrap.setup_component( + self.hass, + litejet.DOMAIN, + { + 'litejet': { + 'port': '/tmp/this_will_be_mocked' + } + }) + self.hass.block_till_done() + + def teardown_method(self, method): + """Stop everything that was started.""" + self.hass.stop() + + def scene(self): + return self.hass.states.get(ENTITY_SCENE) + + def other_scene(self): + return self.hass.states.get(ENTITY_OTHER_SCENE) + + def test_activate(self): + """Test activating the scene.""" + + scene.activate(self.hass, ENTITY_SCENE) + self.hass.block_till_done() + self.mock_lj.activate_scene.assert_called_once_with( + ENTITY_SCENE_NUMBER) diff --git a/tests/components/switch/test_litejet.py b/tests/components/switch/test_litejet.py new file mode 100644 index 00000000000..55d468bccd4 --- /dev/null +++ b/tests/components/switch/test_litejet.py @@ -0,0 +1,142 @@ +"""The tests for the litejet component.""" +import logging +import unittest +from unittest import mock + +from homeassistant import bootstrap +from homeassistant.components import litejet +from tests.common import get_test_home_assistant +import homeassistant.components.switch as switch + +_LOGGER = logging.getLogger(__name__) + +ENTITY_SWITCH = 'switch.mock_switch_1' +ENTITY_SWITCH_NUMBER = 1 +ENTITY_OTHER_SWITCH = 'switch.mock_switch_2' +ENTITY_OTHER_SWITCH_NUMBER = 2 + + +class TestLiteJetSwitch(unittest.TestCase): + """Test the litejet component.""" + + @mock.patch('pylitejet.LiteJet') + def setup_method(self, method, mock_pylitejet): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + self.hass.start() + + self.switch_pressed_callbacks = {} + self.switch_released_callbacks = {} + + def get_switch_name(number): + return "Mock Switch #"+str(number) + + def on_switch_pressed(number, callback): + self.switch_pressed_callbacks[number] = callback + + def on_switch_released(number, callback): + self.switch_released_callbacks[number] = callback + + self.mock_lj = mock_pylitejet.return_value + self.mock_lj.loads.return_value = range(0) + self.mock_lj.button_switches.return_value = range(1, 3) + self.mock_lj.all_switches.return_value = range(1, 6) + self.mock_lj.scenes.return_value = range(0) + self.mock_lj.get_switch_name.side_effect = get_switch_name + self.mock_lj.on_switch_pressed.side_effect = on_switch_pressed + self.mock_lj.on_switch_released.side_effect = on_switch_released + + config = { + 'litejet': { + 'port': '/tmp/this_will_be_mocked', + } + } + if method == self.test_include_switches_False: + config['litejet']['include_switches'] = False + elif method != self.test_include_switches_unspecified: + config['litejet']['include_switches'] = True + + assert bootstrap.setup_component(self.hass, litejet.DOMAIN, config) + self.hass.block_till_done() + + def teardown_method(self, method): + """Stop everything that was started.""" + self.hass.stop() + + def switch(self): + return self.hass.states.get(ENTITY_SWITCH) + + def other_switch(self): + return self.hass.states.get(ENTITY_OTHER_SWITCH) + + def test_include_switches_unspecified(self): + """Test that switches are ignored by default.""" + + self.mock_lj.button_switches.assert_not_called() + self.mock_lj.all_switches.assert_not_called() + + def test_include_switches_False(self): + """Test that switches can be explicitly ignored.""" + + self.mock_lj.button_switches.assert_not_called() + self.mock_lj.all_switches.assert_not_called() + + def test_on_off(self): + """Test turning the switch on and off.""" + + assert self.switch().state == 'off' + assert self.other_switch().state == 'off' + + assert not switch.is_on(self.hass, ENTITY_SWITCH) + + switch.turn_on(self.hass, ENTITY_SWITCH) + self.hass.block_till_done() + self.mock_lj.press_switch.assert_called_with(ENTITY_SWITCH_NUMBER) + + switch.turn_off(self.hass, ENTITY_SWITCH) + self.hass.block_till_done() + self.mock_lj.release_switch.assert_called_with(ENTITY_SWITCH_NUMBER) + + def test_pressed_event(self): + """Test handling an event from LiteJet.""" + + # Switch 1 + + _LOGGER.info(self.switch_pressed_callbacks[ENTITY_SWITCH_NUMBER]) + self.switch_pressed_callbacks[ENTITY_SWITCH_NUMBER]() + self.hass.block_till_done() + + assert switch.is_on(self.hass, ENTITY_SWITCH) + assert not switch.is_on(self.hass, ENTITY_OTHER_SWITCH) + assert self.switch().state == 'on' + assert self.other_switch().state == 'off' + + # Switch 2 + + self.switch_pressed_callbacks[ENTITY_OTHER_SWITCH_NUMBER]() + self.hass.block_till_done() + + assert switch.is_on(self.hass, ENTITY_OTHER_SWITCH) + assert switch.is_on(self.hass, ENTITY_SWITCH) + assert self.other_switch().state == 'on' + assert self.switch().state == 'on' + + def test_released_event(self): + """Test handling an event from LiteJet.""" + + # Initial state is on. + + self.switch_pressed_callbacks[ENTITY_OTHER_SWITCH_NUMBER]() + self.hass.block_till_done() + + assert switch.is_on(self.hass, ENTITY_OTHER_SWITCH) + + # Event indicates it is off now. + + self.switch_released_callbacks[ENTITY_OTHER_SWITCH_NUMBER]() + self.hass.block_till_done() + + assert not switch.is_on(self.hass, ENTITY_OTHER_SWITCH) + assert not switch.is_on(self.hass, ENTITY_SWITCH) + assert self.other_switch().state == 'off' + assert self.switch().state == 'off' diff --git a/tests/components/test_litejet.py b/tests/components/test_litejet.py new file mode 100644 index 00000000000..6d62e1ab0cd --- /dev/null +++ b/tests/components/test_litejet.py @@ -0,0 +1,42 @@ +"""The tests for the litejet component.""" +import logging +import unittest + +from homeassistant.components import litejet +from tests.common import get_test_home_assistant + +_LOGGER = logging.getLogger(__name__) + + +class TestLiteJet(unittest.TestCase): + """Test the litejet component.""" + + def setup_method(self, method): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + self.hass.start() + self.hass.block_till_done() + + def teardown_method(self, method): + """Stop everything that was started.""" + self.hass.stop() + + def test_is_ignored_unspecified(self): + self.hass.data['litejet_config'] = {} + assert not litejet.is_ignored(self.hass, 'Test') + + def test_is_ignored_empty(self): + self.hass.data['litejet_config'] = { + litejet.CONF_EXCLUDE_NAMES: [] + } + assert not litejet.is_ignored(self.hass, 'Test') + + def test_is_ignored_normal(self): + self.hass.data['litejet_config'] = { + litejet.CONF_EXCLUDE_NAMES: ['Test', 'Other One'] + } + assert litejet.is_ignored(self.hass, 'Test') + assert not litejet.is_ignored(self.hass, 'Other one') + assert not litejet.is_ignored(self.hass, 'Other 0ne') + assert litejet.is_ignored(self.hass, 'Other One There') + assert litejet.is_ignored(self.hass, 'Other One') -- GitLab