542 lines
16 KiB
Python
542 lines
16 KiB
Python
"""Test Z-Wave config panel."""
|
|
import json
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
from homeassistant.bootstrap import async_setup_component
|
|
from homeassistant.components import config
|
|
from homeassistant.components.zwave import DATA_NETWORK, const
|
|
|
|
from tests.mock.zwave import MockEntityValues, MockNode, MockValue
|
|
|
|
VIEW_NAME = "api:config:zwave:device_config"
|
|
|
|
|
|
@pytest.fixture
|
|
def client(loop, hass, hass_client):
|
|
"""Client to communicate with Z-Wave config views."""
|
|
with patch.object(config, "SECTIONS", ["zwave"]):
|
|
loop.run_until_complete(async_setup_component(hass, "config", {}))
|
|
|
|
return loop.run_until_complete(hass_client())
|
|
|
|
|
|
async def test_get_device_config(client):
|
|
"""Test getting device config."""
|
|
|
|
def mock_read(path):
|
|
"""Mock reading data."""
|
|
return {"hello.beer": {"free": "beer"}, "other.entity": {"do": "something"}}
|
|
|
|
with patch("homeassistant.components.config._read", mock_read):
|
|
resp = await client.get("/api/config/zwave/device_config/hello.beer")
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
|
|
assert result == {"free": "beer"}
|
|
|
|
|
|
async def test_update_device_config(client):
|
|
"""Test updating device config."""
|
|
orig_data = {
|
|
"hello.beer": {"ignored": True},
|
|
"other.entity": {"polling_intensity": 2},
|
|
}
|
|
|
|
def mock_read(path):
|
|
"""Mock reading data."""
|
|
return orig_data
|
|
|
|
written = []
|
|
|
|
def mock_write(path, data):
|
|
"""Mock writing data."""
|
|
written.append(data)
|
|
|
|
with patch("homeassistant.components.config._read", mock_read), patch(
|
|
"homeassistant.components.config._write", mock_write
|
|
):
|
|
resp = await client.post(
|
|
"/api/config/zwave/device_config/hello.beer",
|
|
data=json.dumps({"polling_intensity": 2}),
|
|
)
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
assert result == {"result": "ok"}
|
|
|
|
orig_data["hello.beer"]["polling_intensity"] = 2
|
|
|
|
assert written[0] == orig_data
|
|
|
|
|
|
async def test_update_device_config_invalid_key(client):
|
|
"""Test updating device config."""
|
|
resp = await client.post(
|
|
"/api/config/zwave/device_config/invalid_entity",
|
|
data=json.dumps({"polling_intensity": 2}),
|
|
)
|
|
|
|
assert resp.status == 400
|
|
|
|
|
|
async def test_update_device_config_invalid_data(client):
|
|
"""Test updating device config."""
|
|
resp = await client.post(
|
|
"/api/config/zwave/device_config/hello.beer",
|
|
data=json.dumps({"invalid_option": 2}),
|
|
)
|
|
|
|
assert resp.status == 400
|
|
|
|
|
|
async def test_update_device_config_invalid_json(client):
|
|
"""Test updating device config."""
|
|
resp = await client.post(
|
|
"/api/config/zwave/device_config/hello.beer", data="not json"
|
|
)
|
|
|
|
assert resp.status == 400
|
|
|
|
|
|
async def test_get_values(hass, client):
|
|
"""Test getting values on node."""
|
|
node = MockNode(node_id=1)
|
|
value = MockValue(
|
|
value_id=123456,
|
|
node=node,
|
|
label="Test Label",
|
|
instance=1,
|
|
index=2,
|
|
poll_intensity=4,
|
|
)
|
|
values = MockEntityValues(primary=value)
|
|
node2 = MockNode(node_id=2)
|
|
value2 = MockValue(value_id=234567, node=node2, label="Test Label 2")
|
|
values2 = MockEntityValues(primary=value2)
|
|
hass.data[const.DATA_ENTITY_VALUES] = [values, values2]
|
|
|
|
resp = await client.get("/api/zwave/values/1")
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
|
|
assert result == {
|
|
"123456": {
|
|
"label": "Test Label",
|
|
"instance": 1,
|
|
"index": 2,
|
|
"poll_intensity": 4,
|
|
}
|
|
}
|
|
|
|
|
|
async def test_get_groups(hass, client):
|
|
"""Test getting groupdata on node."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=2)
|
|
node.groups.associations = "assoc"
|
|
node.groups.associations_instances = "inst"
|
|
node.groups.label = "the label"
|
|
node.groups.max_associations = "max"
|
|
node.groups = {1: node.groups}
|
|
network.nodes = {2: node}
|
|
|
|
resp = await client.get("/api/zwave/groups/2")
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
|
|
assert result == {
|
|
"1": {
|
|
"association_instances": "inst",
|
|
"associations": "assoc",
|
|
"label": "the label",
|
|
"max_associations": "max",
|
|
}
|
|
}
|
|
|
|
|
|
async def test_get_groups_nogroups(hass, client):
|
|
"""Test getting groupdata on node with no groups."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=2)
|
|
|
|
network.nodes = {2: node}
|
|
|
|
resp = await client.get("/api/zwave/groups/2")
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
|
|
assert result == {}
|
|
|
|
|
|
async def test_get_groups_nonode(hass, client):
|
|
"""Test getting groupdata on nonexisting node."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
network.nodes = {1: 1, 5: 5}
|
|
|
|
resp = await client.get("/api/zwave/groups/2")
|
|
|
|
assert resp.status == 404
|
|
result = await resp.json()
|
|
|
|
assert result == {"message": "Node not found"}
|
|
|
|
|
|
async def test_get_config(hass, client):
|
|
"""Test getting config on node."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=2)
|
|
value = MockValue(index=12, command_class=const.COMMAND_CLASS_CONFIGURATION)
|
|
value.label = "label"
|
|
value.help = "help"
|
|
value.type = "type"
|
|
value.data = "data"
|
|
value.data_items = ["item1", "item2"]
|
|
value.max = "max"
|
|
value.min = "min"
|
|
node.values = {12: value}
|
|
network.nodes = {2: node}
|
|
node.get_values.return_value = node.values
|
|
|
|
resp = await client.get("/api/zwave/config/2")
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
|
|
assert result == {
|
|
"12": {
|
|
"data": "data",
|
|
"data_items": ["item1", "item2"],
|
|
"help": "help",
|
|
"label": "label",
|
|
"max": "max",
|
|
"min": "min",
|
|
"type": "type",
|
|
}
|
|
}
|
|
|
|
|
|
async def test_get_config_noconfig_node(hass, client):
|
|
"""Test getting config on node without config."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=2)
|
|
|
|
network.nodes = {2: node}
|
|
node.get_values.return_value = node.values
|
|
|
|
resp = await client.get("/api/zwave/config/2")
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
|
|
assert result == {}
|
|
|
|
|
|
async def test_get_config_nonode(hass, client):
|
|
"""Test getting config on nonexisting node."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
network.nodes = {1: 1, 5: 5}
|
|
|
|
resp = await client.get("/api/zwave/config/2")
|
|
|
|
assert resp.status == 404
|
|
result = await resp.json()
|
|
|
|
assert result == {"message": "Node not found"}
|
|
|
|
|
|
async def test_get_usercodes_nonode(hass, client):
|
|
"""Test getting usercodes on nonexisting node."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
network.nodes = {1: 1, 5: 5}
|
|
|
|
resp = await client.get("/api/zwave/usercodes/2")
|
|
|
|
assert resp.status == 404
|
|
result = await resp.json()
|
|
|
|
assert result == {"message": "Node not found"}
|
|
|
|
|
|
async def test_get_usercodes(hass, client):
|
|
"""Test getting usercodes on node."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=18, command_classes=[const.COMMAND_CLASS_USER_CODE])
|
|
value = MockValue(index=0, command_class=const.COMMAND_CLASS_USER_CODE)
|
|
value.genre = const.GENRE_USER
|
|
value.label = "label"
|
|
value.data = "1234"
|
|
node.values = {0: value}
|
|
network.nodes = {18: node}
|
|
node.get_values.return_value = node.values
|
|
|
|
resp = await client.get("/api/zwave/usercodes/18")
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
|
|
assert result == {"0": {"code": "1234", "label": "label", "length": 4}}
|
|
|
|
|
|
async def test_get_usercode_nousercode_node(hass, client):
|
|
"""Test getting usercodes on node without usercodes."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=18)
|
|
|
|
network.nodes = {18: node}
|
|
node.get_values.return_value = node.values
|
|
|
|
resp = await client.get("/api/zwave/usercodes/18")
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
|
|
assert result == {}
|
|
|
|
|
|
async def test_get_usercodes_no_genreuser(hass, client):
|
|
"""Test getting usercodes on node missing genre user."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=18, command_classes=[const.COMMAND_CLASS_USER_CODE])
|
|
value = MockValue(index=0, command_class=const.COMMAND_CLASS_USER_CODE)
|
|
value.genre = const.GENRE_SYSTEM
|
|
value.label = "label"
|
|
value.data = "1234"
|
|
node.values = {0: value}
|
|
network.nodes = {18: node}
|
|
node.get_values.return_value = node.values
|
|
|
|
resp = await client.get("/api/zwave/usercodes/18")
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
|
|
assert result == {}
|
|
|
|
|
|
async def test_save_config_no_network(hass, client):
|
|
"""Test saving configuration without network data."""
|
|
resp = await client.post("/api/zwave/saveconfig")
|
|
|
|
assert resp.status == 404
|
|
result = await resp.json()
|
|
assert result == {"message": "No Z-Wave network data found"}
|
|
|
|
|
|
async def test_save_config(hass, client):
|
|
"""Test saving configuration."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
|
|
resp = await client.post("/api/zwave/saveconfig")
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
assert network.write_config.called
|
|
assert result == {"message": "Z-Wave configuration saved to file."}
|
|
|
|
|
|
async def test_get_protection_values(hass, client):
|
|
"""Test getting protection values on node."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=18, command_classes=[const.COMMAND_CLASS_PROTECTION])
|
|
value = MockValue(
|
|
value_id=123456,
|
|
index=0,
|
|
instance=1,
|
|
command_class=const.COMMAND_CLASS_PROTECTION,
|
|
)
|
|
value.label = "Protection Test"
|
|
value.data_items = [
|
|
"Unprotected",
|
|
"Protection by Sequence",
|
|
"No Operation Possible",
|
|
]
|
|
value.data = "Unprotected"
|
|
network.nodes = {18: node}
|
|
node.value = value
|
|
|
|
node.get_protection_item.return_value = "Unprotected"
|
|
node.get_protection_items.return_value = value.data_items
|
|
node.get_protections.return_value = {value.value_id: "Object"}
|
|
|
|
resp = await client.get("/api/zwave/protection/18")
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
assert node.get_protections.called
|
|
assert node.get_protection_item.called
|
|
assert node.get_protection_items.called
|
|
assert result == {
|
|
"value_id": "123456",
|
|
"selected": "Unprotected",
|
|
"options": ["Unprotected", "Protection by Sequence", "No Operation Possible"],
|
|
}
|
|
|
|
|
|
async def test_get_protection_values_nonexisting_node(hass, client):
|
|
"""Test getting protection values on node with wrong nodeid."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=18, command_classes=[const.COMMAND_CLASS_PROTECTION])
|
|
value = MockValue(
|
|
value_id=123456,
|
|
index=0,
|
|
instance=1,
|
|
command_class=const.COMMAND_CLASS_PROTECTION,
|
|
)
|
|
value.label = "Protection Test"
|
|
value.data_items = [
|
|
"Unprotected",
|
|
"Protection by Sequence",
|
|
"No Operation Possible",
|
|
]
|
|
value.data = "Unprotected"
|
|
network.nodes = {17: node}
|
|
node.value = value
|
|
|
|
resp = await client.get("/api/zwave/protection/18")
|
|
|
|
assert resp.status == 404
|
|
result = await resp.json()
|
|
assert not node.get_protections.called
|
|
assert not node.get_protection_item.called
|
|
assert not node.get_protection_items.called
|
|
assert result == {"message": "Node not found"}
|
|
|
|
|
|
async def test_get_protection_values_without_protectionclass(hass, client):
|
|
"""Test getting protection values on node without protectionclass."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=18)
|
|
value = MockValue(value_id=123456, index=0, instance=1)
|
|
network.nodes = {18: node}
|
|
node.value = value
|
|
|
|
resp = await client.get("/api/zwave/protection/18")
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
assert not node.get_protections.called
|
|
assert not node.get_protection_item.called
|
|
assert not node.get_protection_items.called
|
|
assert result == {}
|
|
|
|
|
|
async def test_set_protection_value(hass, client):
|
|
"""Test setting protection value on node."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=18, command_classes=[const.COMMAND_CLASS_PROTECTION])
|
|
value = MockValue(
|
|
value_id=123456,
|
|
index=0,
|
|
instance=1,
|
|
command_class=const.COMMAND_CLASS_PROTECTION,
|
|
)
|
|
value.label = "Protection Test"
|
|
value.data_items = [
|
|
"Unprotected",
|
|
"Protection by Sequence",
|
|
"No Operation Possible",
|
|
]
|
|
value.data = "Unprotected"
|
|
network.nodes = {18: node}
|
|
node.value = value
|
|
|
|
resp = await client.post(
|
|
"/api/zwave/protection/18",
|
|
data=json.dumps({"value_id": "123456", "selection": "Protection by Sequence"}),
|
|
)
|
|
|
|
assert resp.status == 200
|
|
result = await resp.json()
|
|
assert node.set_protection.called
|
|
assert result == {"message": "Protection setting succsessfully set"}
|
|
|
|
|
|
async def test_set_protection_value_failed(hass, client):
|
|
"""Test setting protection value failed on node."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=18, command_classes=[const.COMMAND_CLASS_PROTECTION])
|
|
value = MockValue(
|
|
value_id=123456,
|
|
index=0,
|
|
instance=1,
|
|
command_class=const.COMMAND_CLASS_PROTECTION,
|
|
)
|
|
value.label = "Protection Test"
|
|
value.data_items = [
|
|
"Unprotected",
|
|
"Protection by Sequence",
|
|
"No Operation Possible",
|
|
]
|
|
value.data = "Unprotected"
|
|
network.nodes = {18: node}
|
|
node.value = value
|
|
node.set_protection.return_value = False
|
|
|
|
resp = await client.post(
|
|
"/api/zwave/protection/18",
|
|
data=json.dumps({"value_id": "123456", "selection": "Protecton by Sequence"}),
|
|
)
|
|
|
|
assert resp.status == 202
|
|
result = await resp.json()
|
|
assert node.set_protection.called
|
|
assert result == {"message": "Protection setting did not complete"}
|
|
|
|
|
|
async def test_set_protection_value_nonexisting_node(hass, client):
|
|
"""Test setting protection value on nonexisting node."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=17, command_classes=[const.COMMAND_CLASS_PROTECTION])
|
|
value = MockValue(
|
|
value_id=123456,
|
|
index=0,
|
|
instance=1,
|
|
command_class=const.COMMAND_CLASS_PROTECTION,
|
|
)
|
|
value.label = "Protection Test"
|
|
value.data_items = [
|
|
"Unprotected",
|
|
"Protection by Sequence",
|
|
"No Operation Possible",
|
|
]
|
|
value.data = "Unprotected"
|
|
network.nodes = {17: node}
|
|
node.value = value
|
|
node.set_protection.return_value = False
|
|
|
|
resp = await client.post(
|
|
"/api/zwave/protection/18",
|
|
data=json.dumps({"value_id": "123456", "selection": "Protecton by Sequence"}),
|
|
)
|
|
|
|
assert resp.status == 404
|
|
result = await resp.json()
|
|
assert not node.set_protection.called
|
|
assert result == {"message": "Node not found"}
|
|
|
|
|
|
async def test_set_protection_value_missing_class(hass, client):
|
|
"""Test setting protection value on node without protectionclass."""
|
|
network = hass.data[DATA_NETWORK] = MagicMock()
|
|
node = MockNode(node_id=17)
|
|
value = MockValue(value_id=123456, index=0, instance=1)
|
|
network.nodes = {17: node}
|
|
node.value = value
|
|
node.set_protection.return_value = False
|
|
|
|
resp = await client.post(
|
|
"/api/zwave/protection/17",
|
|
data=json.dumps({"value_id": "123456", "selection": "Protecton by Sequence"}),
|
|
)
|
|
|
|
assert resp.status == 404
|
|
result = await resp.json()
|
|
assert not node.set_protection.called
|
|
assert result == {"message": "No protection commandclass on this node"}
|