"""The tests for the litejet component.""" import logging from unittest import mock from datetime import timedelta import pytest from homeassistant import setup import homeassistant.util.dt as dt_util from homeassistant.components import litejet import homeassistant.components.automation as automation from tests.common import async_fire_time_changed, async_mock_service _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 @pytest.fixture def calls(hass): """Track calls to a mock serivce.""" return async_mock_service(hass, "test", "automation") def get_switch_name(number): """Get a mock switch name.""" return "Mock Switch #" + str(number) @pytest.fixture def mock_lj(hass): """Initialize components.""" with mock.patch("pylitejet.LiteJet") as mock_pylitejet: mock_lj = mock_pylitejet.return_value mock_lj.switch_pressed_callbacks = {} mock_lj.switch_released_callbacks = {} def on_switch_pressed(number, callback): mock_lj.switch_pressed_callbacks[number] = callback def on_switch_released(number, callback): mock_lj.switch_released_callbacks[number] = callback mock_lj.loads.return_value = range(0) mock_lj.button_switches.return_value = range(1, 3) mock_lj.all_switches.return_value = range(1, 6) mock_lj.scenes.return_value = range(0) mock_lj.get_switch_name.side_effect = get_switch_name mock_lj.on_switch_pressed.side_effect = on_switch_pressed mock_lj.on_switch_released.side_effect = on_switch_released config = {"litejet": {"port": "/tmp/this_will_be_mocked"}} assert hass.loop.run_until_complete( setup.async_setup_component(hass, litejet.DOMAIN, config) ) mock_lj.start_time = dt_util.utcnow() mock_lj.last_delta = timedelta(0) return mock_lj async def simulate_press(hass, mock_lj, number): """Test to simulate a press.""" _LOGGER.info("*** simulate press of %d", number) callback = mock_lj.switch_pressed_callbacks.get(number) with mock.patch( "homeassistant.helpers.condition.dt_util.utcnow", return_value=mock_lj.start_time + mock_lj.last_delta, ): if callback is not None: await hass.async_add_job(callback) await hass.async_block_till_done() async def simulate_release(hass, mock_lj, number): """Test to simulate releasing.""" _LOGGER.info("*** simulate release of %d", number) callback = mock_lj.switch_released_callbacks.get(number) with mock.patch( "homeassistant.helpers.condition.dt_util.utcnow", return_value=mock_lj.start_time + mock_lj.last_delta, ): if callback is not None: await hass.async_add_job(callback) await hass.async_block_till_done() async def simulate_time(hass, mock_lj, delta): """Test to simulate time.""" _LOGGER.info( "*** simulate time change by %s: %s", delta, mock_lj.start_time + delta ) mock_lj.last_delta = delta with mock.patch( "homeassistant.helpers.condition.dt_util.utcnow", return_value=mock_lj.start_time + delta, ): _LOGGER.info("now=%s", dt_util.utcnow()) async_fire_time_changed(hass, mock_lj.start_time + delta) await hass.async_block_till_done() _LOGGER.info("done with now=%s", dt_util.utcnow()) async def setup_automation(hass, trigger): """Test setting up the automation.""" assert await setup.async_setup_component( hass, automation.DOMAIN, { automation.DOMAIN: [ { "alias": "My Test", "trigger": trigger, "action": {"service": "test.automation"}, } ] }, ) await hass.async_block_till_done() async def test_simple(hass, calls, mock_lj): """Test the simplest form of a LiteJet trigger.""" await setup_automation( hass, {"platform": "litejet", "number": ENTITY_OTHER_SWITCH_NUMBER} ) await simulate_press(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) await simulate_release(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 1 async def test_held_more_than_short(hass, calls, mock_lj): """Test a too short hold.""" await setup_automation( hass, { "platform": "litejet", "number": ENTITY_OTHER_SWITCH_NUMBER, "held_more_than": {"milliseconds": "200"}, }, ) await simulate_press(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) await simulate_time(hass, mock_lj, timedelta(seconds=0.1)) await simulate_release(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 0 async def test_held_more_than_long(hass, calls, mock_lj): """Test a hold that is long enough.""" await setup_automation( hass, { "platform": "litejet", "number": ENTITY_OTHER_SWITCH_NUMBER, "held_more_than": {"milliseconds": "200"}, }, ) await simulate_press(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 0 await simulate_time(hass, mock_lj, timedelta(seconds=0.3)) assert len(calls) == 1 await simulate_release(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 1 async def test_held_less_than_short(hass, calls, mock_lj): """Test a hold that is short enough.""" await setup_automation( hass, { "platform": "litejet", "number": ENTITY_OTHER_SWITCH_NUMBER, "held_less_than": {"milliseconds": "200"}, }, ) await simulate_press(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) await simulate_time(hass, mock_lj, timedelta(seconds=0.1)) assert len(calls) == 0 await simulate_release(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 1 async def test_held_less_than_long(hass, calls, mock_lj): """Test a hold that is too long.""" await setup_automation( hass, { "platform": "litejet", "number": ENTITY_OTHER_SWITCH_NUMBER, "held_less_than": {"milliseconds": "200"}, }, ) await simulate_press(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 0 await simulate_time(hass, mock_lj, timedelta(seconds=0.3)) assert len(calls) == 0 await simulate_release(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 0 async def test_held_in_range_short(hass, calls, mock_lj): """Test an in-range trigger with a too short hold.""" await setup_automation( hass, { "platform": "litejet", "number": ENTITY_OTHER_SWITCH_NUMBER, "held_more_than": {"milliseconds": "100"}, "held_less_than": {"milliseconds": "300"}, }, ) await simulate_press(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) await simulate_time(hass, mock_lj, timedelta(seconds=0.05)) await simulate_release(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 0 async def test_held_in_range_just_right(hass, calls, mock_lj): """Test an in-range trigger with a just right hold.""" await setup_automation( hass, { "platform": "litejet", "number": ENTITY_OTHER_SWITCH_NUMBER, "held_more_than": {"milliseconds": "100"}, "held_less_than": {"milliseconds": "300"}, }, ) await simulate_press(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 0 await simulate_time(hass, mock_lj, timedelta(seconds=0.2)) assert len(calls) == 0 await simulate_release(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 1 async def test_held_in_range_long(hass, calls, mock_lj): """Test an in-range trigger with a too long hold.""" await setup_automation( hass, { "platform": "litejet", "number": ENTITY_OTHER_SWITCH_NUMBER, "held_more_than": {"milliseconds": "100"}, "held_less_than": {"milliseconds": "300"}, }, ) await simulate_press(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 0 await simulate_time(hass, mock_lj, timedelta(seconds=0.4)) assert len(calls) == 0 await simulate_release(hass, mock_lj, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 0