From 32bb950b5f4e0cac647353c2b4a7940f908fc73f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 13 Oct 2015 22:36:21 -0700 Subject: [PATCH] Add tests for manual alarm control panel platform --- .../components/alarm_control_panel/manual.py | 99 ++++--- tests/__init__.py | 2 - .../alarm_control_panel/test_manual.py | 258 ++++++++++++++++++ 3 files changed, 305 insertions(+), 54 deletions(-) create mode 100644 tests/components/alarm_control_panel/test_manual.py diff --git a/homeassistant/components/alarm_control_panel/manual.py b/homeassistant/components/alarm_control_panel/manual.py index 2aee8b89e17..63370de352c 100644 --- a/homeassistant/components/alarm_control_panel/manual.py +++ b/homeassistant/components/alarm_control_panel/manual.py @@ -46,11 +46,10 @@ class ManualAlarm(alarm.AlarmControlPanel): self._state = STATE_ALARM_DISARMED self._hass = hass self._name = name - self._code = code + self._code = str(code) if code else None self._pending_time = datetime.timedelta(seconds=pending_time) self._trigger_time = datetime.timedelta(seconds=trigger_time) self._state_ts = None - self._pending_to = None @property def should_poll(self): @@ -65,6 +64,15 @@ class ManualAlarm(alarm.AlarmControlPanel): @property def state(self): """ Returns the state of the device. """ + if self._state in (STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY) and \ + self._pending_time and self._state_ts + self._pending_time > \ + dt_util.utcnow(): + return STATE_ALARM_PENDING + + if self._state == STATE_ALARM_TRIGGERED and self._trigger_time and \ + self._state_ts + self._trigger_time > dt_util.utcnow(): + return STATE_ALARM_PENDING + return self._state @property @@ -72,70 +80,57 @@ class ManualAlarm(alarm.AlarmControlPanel): """ One or more characters. """ return None if self._code is None else '.+' - def update_state(self, state, pending_to): - """ Changes between state with delay. """ - self._state = state - self._state_ts = dt_util.utcnow() - self._pending_to = pending_to - self.update_ha_state() - def alarm_disarm(self, code=None): """ Send disarm command. """ - if code == str(self._code) or self.code_format is None: - self.update_state(STATE_ALARM_DISARMED, None) - else: - _LOGGER.warning("Wrong code entered while disarming!") + if not self._validate_code(code, STATE_ALARM_DISARMED): + return + + self._state = STATE_ALARM_DISARMED + self._state_ts = dt_util.utcnow() + self.update_ha_state() def alarm_arm_home(self, code=None): """ Send arm home command. """ - if code == str(self._code) or self.code_format is None: - self.update_state(STATE_ALARM_PENDING, STATE_ALARM_ARMED_HOME) + if not self._validate_code(code, STATE_ALARM_ARMED_HOME): + return - def delayed_alarm_arm_home(event_time): - """ Callback for delayed action. """ - if self._pending_to == STATE_ALARM_ARMED_HOME and \ - dt_util.utcnow() - self._state_ts >= self._pending_time: - self.update_state(STATE_ALARM_ARMED_HOME, None) + self._state = STATE_ALARM_ARMED_HOME + self._state_ts = dt_util.utcnow() + self.update_ha_state() + + if self._pending_time: track_point_in_time( - self._hass, delayed_alarm_arm_home, - dt_util.utcnow() + self._pending_time) - else: - _LOGGER.warning("Wrong code entered while arming home!") + self._hass, self.update_ha_state, + self._state_ts + self._pending_time) def alarm_arm_away(self, code=None): """ Send arm away command. """ - if code == str(self._code) or self.code_format is None: - self.update_state(STATE_ALARM_PENDING, STATE_ALARM_ARMED_AWAY) + if not self._validate_code(code, STATE_ALARM_ARMED_AWAY): + return - def delayed_alarm_arm_away(event_time): - """ Callback for delayed action. """ - if self._pending_to == STATE_ALARM_ARMED_AWAY and \ - dt_util.utcnow() - self._state_ts >= self._pending_time: - self.update_state(STATE_ALARM_ARMED_AWAY, None) + self._state = STATE_ALARM_ARMED_AWAY + self._state_ts = dt_util.utcnow() + self.update_ha_state() + + if self._pending_time: track_point_in_time( - self._hass, delayed_alarm_arm_away, - dt_util.utcnow() + self._pending_time) - else: - _LOGGER.warning("Wrong code entered while arming away!") + self._hass, self.update_ha_state, + self._state_ts + self._pending_time) def alarm_trigger(self, code=None): """ Send alarm trigger command. No code needed. """ - self.update_state(STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED) + self._state = STATE_ALARM_TRIGGERED + self._state_ts = dt_util.utcnow() + self.update_ha_state() - def delayed_alarm_trigger(event_time): - """ callback for delayed action """ - if self._pending_to == STATE_ALARM_TRIGGERED and \ - dt_util.utcnow() - self._state_ts >= self._pending_time: - self.update_state(STATE_ALARM_TRIGGERED, STATE_ALARM_DISARMED) + if self._trigger_time: + track_point_in_time( + self._hass, self.update_ha_state, + self._state_ts + self._trigger_time) - def delayed_alarm_disarm(event_time): - """ Callback for delayed action. """ - if self._pending_to == STATE_ALARM_DISARMED and \ - dt_util.utcnow() - self._state_ts >= self._trigger_time: - self.update_state(STATE_ALARM_DISARMED, None) - track_point_in_time( - self._hass, delayed_alarm_disarm, - dt_util.utcnow() + self._trigger_time) - track_point_in_time( - self._hass, delayed_alarm_trigger, - dt_util.utcnow() + self._pending_time) + def _validate_code(self, code, state): + """ Validate given code. """ + check = self._code is None or code == self._code + if not check: + _LOGGER.warning('Invalid code given for %s', state) + return check diff --git a/tests/__init__.py b/tests/__init__.py index c39a22e0b57..e69de29bb2d 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,2 +0,0 @@ -import logging -logging.disable(logging.CRITICAL) diff --git a/tests/components/alarm_control_panel/test_manual.py b/tests/components/alarm_control_panel/test_manual.py new file mode 100644 index 00000000000..69514babb35 --- /dev/null +++ b/tests/components/alarm_control_panel/test_manual.py @@ -0,0 +1,258 @@ +""" +tests.components.alarm_control_panel.test_manual +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tests manual alarm control panel component. +""" +from datetime import timedelta +import unittest +from unittest.mock import patch + +import homeassistant.core as ha +from homeassistant.const import ( + STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY, + STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED) +from homeassistant.components import alarm_control_panel +import homeassistant.util.dt as dt_util + +from tests.common import fire_time_changed + +CODE = 'HELLO_CODE' + + +class TestAlarmControlPanelManual(unittest.TestCase): + """ Test the demo module. """ + + def setUp(self): # pylint: disable=invalid-name + self.hass = ha.HomeAssistant() + + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.hass.stop() + + def test_arm_home_no_pending(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'pending_time': 0 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_home(self.hass, CODE) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_HOME, + self.hass.states.get(entity_id).state) + + def test_arm_home_with_pending(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'pending_time': 1 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_home(self.hass, CODE, entity_id) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=1) + with patch(('homeassistant.components.alarm_control_panel.manual.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_HOME, + self.hass.states.get(entity_id).state) + + def test_arm_home_with_invalid_code(self): + """ Attempt to arm home without a valid code. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'pending_time': 1 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_home(self.hass, CODE + '2') + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + def test_arm_away_no_pending(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'pending_time': 0 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_away(self.hass, CODE, entity_id) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_AWAY, + self.hass.states.get(entity_id).state) + + def test_arm_away_with_pending(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'pending_time': 1 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_away(self.hass, CODE) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=1) + with patch(('homeassistant.components.alarm_control_panel.manual.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_AWAY, + self.hass.states.get(entity_id).state) + + def test_arm_away_with_invalid_code(self): + """ Attempt to arm away without a valid code. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'pending_time': 1 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_away(self.hass, CODE + '2') + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + def test_trigger_no_pending(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'trigger_time': 0 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_TRIGGERED, + self.hass.states.get(entity_id).state) + + def test_trigger_with_pending(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'trigger_time': 1 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_trigger(self.hass) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=1) + with patch(('homeassistant.components.alarm_control_panel.manual.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_TRIGGERED, + self.hass.states.get(entity_id).state) + + def test_disarm_while_pending_trigger(self): + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'trigger_time': 5 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_trigger(self.hass) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_disarm(self.hass, entity_id=entity_id) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=5) + with patch(('homeassistant.components.alarm_control_panel.manual.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state)