Add automation config validation

* Add automation config validation

* Remove unnecessary dict validator

* Downgrade voluptuous to 0.8.9

* Fix linting

* Address issues
This commit is contained in:
Paulus Schoutsen 2016-04-04 12:18:58 -07:00
parent cbe9a7d2a3
commit 8ef542927f
24 changed files with 570 additions and 443 deletions

View file

@ -3,9 +3,9 @@ import unittest
from datetime import timedelta
from unittest.mock import patch
from homeassistant.bootstrap import _setup_component
import homeassistant.util.dt as dt_util
import homeassistant.components.automation as automation
import homeassistant.components.automation.state as state
from tests.common import fire_time_changed, get_test_home_assistant
@ -16,6 +16,7 @@ class TestAutomationState(unittest.TestCase):
def setUp(self): # pylint: disable=invalid-name
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.hass.config.components.append('group')
self.hass.states.set('test.entity', 'hello')
self.calls = []
@ -30,7 +31,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_fires_on_entity_change(self):
"""Test for firing on entity change."""
self.assertTrue(automation.setup(self.hass, {
assert _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
@ -40,7 +41,7 @@ class TestAutomationState(unittest.TestCase):
'service': 'test.automation'
}
}
}))
})
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
@ -48,7 +49,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_fires_on_entity_change_with_from_filter(self):
"""Test for firing on entity change with filter."""
self.assertTrue(automation.setup(self.hass, {
assert _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
@ -59,7 +60,7 @@ class TestAutomationState(unittest.TestCase):
'service': 'test.automation'
}
}
}))
})
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
@ -67,7 +68,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_fires_on_entity_change_with_to_filter(self):
"""Test for firing on entity change with no filter."""
self.assertTrue(automation.setup(self.hass, {
assert _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
@ -78,7 +79,7 @@ class TestAutomationState(unittest.TestCase):
'service': 'test.automation'
}
}
}))
})
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
@ -86,7 +87,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_fires_on_entity_change_with_state_filter(self):
"""Test for firing on entity change with state filter."""
self.assertTrue(automation.setup(self.hass, {
assert _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
@ -97,7 +98,7 @@ class TestAutomationState(unittest.TestCase):
'service': 'test.automation'
}
}
}))
})
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
@ -105,7 +106,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_fires_on_entity_change_with_both_filters(self):
"""Test for firing if both filters are a non match."""
self.assertTrue(automation.setup(self.hass, {
assert _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
@ -117,7 +118,7 @@ class TestAutomationState(unittest.TestCase):
'service': 'test.automation'
}
}
}))
})
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
@ -125,7 +126,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_not_fires_if_to_filter_not_match(self):
"""Test for not firing if to filter is not a match."""
self.assertTrue(automation.setup(self.hass, {
assert _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
@ -137,7 +138,7 @@ class TestAutomationState(unittest.TestCase):
'service': 'test.automation'
}
}
}))
})
self.hass.states.set('test.entity', 'moon')
self.hass.pool.block_till_done()
@ -147,7 +148,7 @@ class TestAutomationState(unittest.TestCase):
"""Test for not firing if from filter is not a match."""
self.hass.states.set('test.entity', 'bye')
self.assertTrue(automation.setup(self.hass, {
assert _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
@ -159,7 +160,7 @@ class TestAutomationState(unittest.TestCase):
'service': 'test.automation'
}
}
}))
})
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
@ -167,7 +168,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_not_fires_if_entity_not_match(self):
"""Test for not firing if entity is not matching."""
self.assertTrue(automation.setup(self.hass, {
assert _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
@ -177,7 +178,7 @@ class TestAutomationState(unittest.TestCase):
'service': 'test.automation'
}
}
}))
})
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
@ -187,7 +188,7 @@ class TestAutomationState(unittest.TestCase):
"""Test for to action."""
entity_id = 'domain.test_entity'
test_state = 'new_state'
automation.setup(self.hass, {
assert _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'event',
@ -218,48 +219,68 @@ class TestAutomationState(unittest.TestCase):
def test_if_fails_setup_if_to_boolean_value(self):
"""Test for setup failure for boolean to."""
self.assertFalse(state.trigger(
self.hass, {
'platform': 'state',
'entity_id': 'test.entity',
'to': True,
}, lambda x: x))
assert not _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
'entity_id': 'test.entity',
'to': True,
},
'action': {
'service': 'homeassistant.turn_on',
}
}})
def test_if_fails_setup_if_from_boolean_value(self):
"""Test for setup failure for boolean from."""
self.assertFalse(state.trigger(
self.hass, {
'platform': 'state',
'entity_id': 'test.entity',
'from': True,
}, lambda x: x))
assert not _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
'entity_id': 'test.entity',
'from': True,
},
'action': {
'service': 'homeassistant.turn_on',
}
}})
def test_if_fails_setup_bad_for(self):
"""Test for setup failure for bad for."""
self.assertFalse(state.trigger(
self.hass, {
'platform': 'state',
'entity_id': 'test.entity',
'to': 'world',
'for': {
'invalid': 5
assert not _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
'entity_id': 'test.entity',
'to': 'world',
'for': {
'invalid': 5
},
},
}, lambda x: x))
'action': {
'service': 'homeassistant.turn_on',
}
}})
def test_if_fails_setup_for_without_to(self):
"""Test for setup failures for missing to."""
self.assertFalse(state.trigger(
self.hass, {
'platform': 'state',
'entity_id': 'test.entity',
'for': {
'seconds': 5
assert not _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
'entity_id': 'test.entity',
'for': {
'seconds': 5
},
},
}, lambda x: x))
'action': {
'service': 'homeassistant.turn_on',
}
}})
def test_if_not_fires_on_entity_change_with_for(self):
"""Test for not firing on entity change with for."""
self.assertTrue(automation.setup(self.hass, {
assert _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
@ -273,7 +294,7 @@ class TestAutomationState(unittest.TestCase):
'service': 'test.automation'
}
}
}))
})
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
@ -285,7 +306,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_fires_on_entity_change_with_for(self):
"""Test for firing on entity change with for."""
self.assertTrue(automation.setup(self.hass, {
assert _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'state',
@ -299,7 +320,7 @@ class TestAutomationState(unittest.TestCase):
'service': 'test.automation'
}
}
}))
})
self.hass.states.set('test.entity', 'world')
self.hass.pool.block_till_done()
@ -314,7 +335,7 @@ class TestAutomationState(unittest.TestCase):
with patch('homeassistant.core.dt_util.utcnow') as mock_utcnow:
mock_utcnow.return_value = point1
self.hass.states.set('test.entity', 'on')
self.assertTrue(automation.setup(self.hass, {
assert _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'event',
@ -328,12 +349,9 @@ class TestAutomationState(unittest.TestCase):
'seconds': 5
},
},
'action': {
'service': 'test.automation'
}
'action': {'service': 'test.automation'},
}
}))
})
# not enough time has passed
self.hass.bus.fire('test_event')
@ -348,21 +366,32 @@ class TestAutomationState(unittest.TestCase):
def test_if_fails_setup_for_without_time(self):
"""Test for setup failure if no time is provided."""
self.assertIsNone(state.if_action(
self.hass, {
'platform': 'state',
'entity_id': 'test.entity',
'state': 'on',
'for': {},
}))
assert not _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'event',
'event_type': 'bla'
},
'condition': {
'platform': 'state',
'entity_id': 'test.entity',
'state': 'on',
'for': {},
},
'action': {'service': 'test.automation'},
}})
def test_if_fails_setup_for_without_entity(self):
"""Test for setup failure if no entity is provided."""
self.assertIsNone(state.if_action(
self.hass, {
'platform': 'state',
'state': 'on',
'for': {
'seconds': 5
assert not _setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {'event_type': 'bla'},
'condition': {
'platform': 'state',
'state': 'on',
'for': {
'seconds': 5
},
},
}))
'action': {'service': 'test.automation'},
}})