2019-03-24 15:16:50 +00:00
|
|
|
"""Test Axis device."""
|
2020-01-02 23:02:59 +00:00
|
|
|
from copy import deepcopy
|
2019-03-24 15:16:50 +00:00
|
|
|
|
2020-01-02 23:02:59 +00:00
|
|
|
import axis as axislib
|
2020-05-14 08:49:27 +00:00
|
|
|
from axis.event_stream import OPERATION_INITIALIZED
|
2019-03-24 15:16:50 +00:00
|
|
|
import pytest
|
|
|
|
|
2020-01-02 23:02:59 +00:00
|
|
|
from homeassistant import config_entries
|
|
|
|
from homeassistant.components import axis
|
2020-05-14 08:49:27 +00:00
|
|
|
from homeassistant.components.axis.const import (
|
|
|
|
CONF_CAMERA,
|
|
|
|
CONF_EVENTS,
|
|
|
|
CONF_MODEL,
|
|
|
|
DOMAIN as AXIS_DOMAIN,
|
|
|
|
)
|
|
|
|
from homeassistant.const import (
|
|
|
|
CONF_HOST,
|
|
|
|
CONF_MAC,
|
|
|
|
CONF_NAME,
|
|
|
|
CONF_PASSWORD,
|
|
|
|
CONF_PORT,
|
|
|
|
CONF_USERNAME,
|
|
|
|
)
|
2019-03-24 15:16:50 +00:00
|
|
|
|
2020-04-30 20:29:50 +00:00
|
|
|
from tests.async_mock import Mock, patch
|
2020-01-03 12:27:14 +00:00
|
|
|
from tests.common import MockConfigEntry
|
|
|
|
|
2020-01-02 23:02:59 +00:00
|
|
|
MAC = "00408C12345"
|
|
|
|
MODEL = "model"
|
|
|
|
NAME = "name"
|
2019-12-08 14:44:04 +00:00
|
|
|
|
2020-05-14 08:49:27 +00:00
|
|
|
ENTRY_OPTIONS = {CONF_CAMERA: True, CONF_EVENTS: True}
|
2019-03-24 15:16:50 +00:00
|
|
|
|
|
|
|
ENTRY_CONFIG = {
|
2020-05-14 08:49:27 +00:00
|
|
|
CONF_HOST: "1.2.3.4",
|
|
|
|
CONF_USERNAME: "username",
|
|
|
|
CONF_PASSWORD: "password",
|
|
|
|
CONF_PORT: 80,
|
|
|
|
CONF_MAC: MAC,
|
|
|
|
CONF_MODEL: MODEL,
|
|
|
|
CONF_NAME: NAME,
|
2019-03-24 15:16:50 +00:00
|
|
|
}
|
|
|
|
|
2020-01-02 23:02:59 +00:00
|
|
|
DEFAULT_BRAND = """root.Brand.Brand=AXIS
|
|
|
|
root.Brand.ProdFullName=AXIS M1065-LW Network Camera
|
|
|
|
root.Brand.ProdNbr=M1065-LW
|
|
|
|
root.Brand.ProdShortName=AXIS M1065-LW
|
|
|
|
root.Brand.ProdType=Network Camera
|
|
|
|
root.Brand.ProdVariant=
|
|
|
|
root.Brand.WebURL=http://www.axis.com
|
|
|
|
"""
|
|
|
|
|
|
|
|
DEFAULT_PORTS = """root.Input.NbrOfInputs=1
|
|
|
|
root.IOPort.I0.Configurable=no
|
|
|
|
root.IOPort.I0.Direction=input
|
|
|
|
root.IOPort.I0.Input.Name=PIR sensor
|
|
|
|
root.IOPort.I0.Input.Trig=closed
|
|
|
|
root.Output.NbrOfOutputs=0
|
|
|
|
"""
|
|
|
|
|
|
|
|
DEFAULT_PROPERTIES = """root.Properties.API.HTTP.Version=3
|
|
|
|
root.Properties.API.Metadata.Metadata=yes
|
|
|
|
root.Properties.API.Metadata.Version=1.0
|
|
|
|
root.Properties.Firmware.BuildDate=Feb 15 2019 09:42
|
|
|
|
root.Properties.Firmware.BuildNumber=26
|
|
|
|
root.Properties.Firmware.Version=9.10.1
|
|
|
|
root.Properties.Image.Format=jpeg,mjpeg,h264
|
|
|
|
root.Properties.Image.NbrOfViews=2
|
|
|
|
root.Properties.Image.Resolution=1920x1080,1280x960,1280x720,1024x768,1024x576,800x600,640x480,640x360,352x240,320x240
|
|
|
|
root.Properties.Image.Rotation=0,180
|
2020-01-03 12:27:14 +00:00
|
|
|
root.Properties.System.SerialNumber=00408C12345
|
2020-01-02 23:02:59 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
async def setup_axis_integration(
|
|
|
|
hass,
|
|
|
|
config=ENTRY_CONFIG,
|
|
|
|
options=ENTRY_OPTIONS,
|
|
|
|
brand=DEFAULT_BRAND,
|
|
|
|
ports=DEFAULT_PORTS,
|
|
|
|
properties=DEFAULT_PROPERTIES,
|
|
|
|
):
|
|
|
|
"""Create the Axis device."""
|
2020-01-03 12:27:14 +00:00
|
|
|
config_entry = MockConfigEntry(
|
2020-05-14 08:49:27 +00:00
|
|
|
domain=AXIS_DOMAIN,
|
2020-01-02 23:02:59 +00:00
|
|
|
data=deepcopy(config),
|
|
|
|
connection_class=config_entries.CONN_CLASS_LOCAL_PUSH,
|
|
|
|
options=deepcopy(options),
|
|
|
|
entry_id="1",
|
2020-01-30 21:20:30 +00:00
|
|
|
version=2,
|
2020-01-02 23:02:59 +00:00
|
|
|
)
|
2020-01-03 12:27:14 +00:00
|
|
|
config_entry.add_to_hass(hass)
|
|
|
|
|
|
|
|
def mock_update_brand(self):
|
|
|
|
self.process_raw(brand)
|
|
|
|
|
|
|
|
def mock_update_ports(self):
|
|
|
|
self.process_raw(ports)
|
2019-03-24 15:16:50 +00:00
|
|
|
|
2020-01-03 12:27:14 +00:00
|
|
|
def mock_update_properties(self):
|
|
|
|
self.process_raw(properties)
|
|
|
|
|
|
|
|
with patch("axis.param_cgi.Brand.update_brand", new=mock_update_brand), patch(
|
|
|
|
"axis.param_cgi.Ports.update_ports", new=mock_update_ports
|
|
|
|
), patch(
|
|
|
|
"axis.param_cgi.Properties.update_properties", new=mock_update_properties
|
|
|
|
), patch(
|
2020-01-02 23:02:59 +00:00
|
|
|
"axis.AxisDevice.start", return_value=True
|
|
|
|
):
|
2020-01-03 12:27:14 +00:00
|
|
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
2020-01-02 23:02:59 +00:00
|
|
|
await hass.async_block_till_done()
|
2019-03-24 15:16:50 +00:00
|
|
|
|
2020-05-14 08:49:27 +00:00
|
|
|
return hass.data[AXIS_DOMAIN].get(config[CONF_MAC])
|
2019-03-24 15:16:50 +00:00
|
|
|
|
|
|
|
|
2020-01-02 23:02:59 +00:00
|
|
|
async def test_device_setup(hass):
|
2019-04-02 18:13:11 +00:00
|
|
|
"""Successful setup."""
|
2020-01-02 23:02:59 +00:00
|
|
|
with patch(
|
|
|
|
"homeassistant.config_entries.ConfigEntries.async_forward_entry_setup",
|
|
|
|
return_value=True,
|
|
|
|
) as forward_entry_setup:
|
|
|
|
device = await setup_axis_integration(hass)
|
|
|
|
|
|
|
|
entry = device.config_entry
|
|
|
|
|
|
|
|
assert len(forward_entry_setup.mock_calls) == 3
|
|
|
|
assert forward_entry_setup.mock_calls[0][1] == (entry, "camera")
|
|
|
|
assert forward_entry_setup.mock_calls[1][1] == (entry, "binary_sensor")
|
|
|
|
assert forward_entry_setup.mock_calls[2][1] == (entry, "switch")
|
|
|
|
|
2020-05-14 08:49:27 +00:00
|
|
|
assert device.host == ENTRY_CONFIG[CONF_HOST]
|
|
|
|
assert device.model == ENTRY_CONFIG[CONF_MODEL]
|
|
|
|
assert device.name == ENTRY_CONFIG[CONF_NAME]
|
|
|
|
assert device.serial == ENTRY_CONFIG[CONF_MAC]
|
2020-01-02 23:02:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_update_address(hass):
|
|
|
|
"""Test update address works."""
|
|
|
|
device = await setup_axis_integration(hass)
|
|
|
|
assert device.api.config.host == "1.2.3.4"
|
|
|
|
|
|
|
|
await hass.config_entries.flow.async_init(
|
2020-05-14 08:49:27 +00:00
|
|
|
AXIS_DOMAIN,
|
2020-01-02 23:02:59 +00:00
|
|
|
data={
|
|
|
|
"host": "2.3.4.5",
|
|
|
|
"port": 80,
|
|
|
|
"hostname": "name",
|
|
|
|
"properties": {"macaddress": MAC},
|
|
|
|
},
|
|
|
|
context={"source": "zeroconf"},
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2019-04-02 18:13:11 +00:00
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
2020-01-02 23:02:59 +00:00
|
|
|
assert device.api.config.host == "2.3.4.5"
|
2019-04-02 18:13:11 +00:00
|
|
|
|
|
|
|
|
2019-04-15 22:06:45 +00:00
|
|
|
async def test_device_unavailable(hass):
|
|
|
|
"""Successful setup."""
|
2020-01-02 23:02:59 +00:00
|
|
|
device = await setup_axis_integration(hass)
|
|
|
|
device.async_connection_status_callback(status=False)
|
|
|
|
assert not device.available
|
2019-04-15 22:06:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_device_reset(hass):
|
|
|
|
"""Successfully reset device."""
|
2020-01-02 23:02:59 +00:00
|
|
|
device = await setup_axis_integration(hass)
|
|
|
|
result = await device.async_reset()
|
|
|
|
assert result is True
|
2019-04-15 22:06:45 +00:00
|
|
|
|
|
|
|
|
2020-01-02 23:02:59 +00:00
|
|
|
async def test_device_not_accessible(hass):
|
2019-03-24 15:16:50 +00:00
|
|
|
"""Failed setup schedules a retry of setup."""
|
2020-01-03 12:27:14 +00:00
|
|
|
with patch.object(axis.device, "get_device", side_effect=axis.errors.CannotConnect):
|
2020-01-02 23:02:59 +00:00
|
|
|
await setup_axis_integration(hass)
|
2020-05-14 08:49:27 +00:00
|
|
|
assert hass.data[AXIS_DOMAIN] == {}
|
2019-03-24 15:16:50 +00:00
|
|
|
|
|
|
|
|
2020-01-02 23:02:59 +00:00
|
|
|
async def test_device_unknown_error(hass):
|
2019-03-24 15:16:50 +00:00
|
|
|
"""Unknown errors are handled."""
|
2020-01-02 23:02:59 +00:00
|
|
|
with patch.object(axis.device, "get_device", side_effect=Exception):
|
|
|
|
await setup_axis_integration(hass)
|
2020-05-14 08:49:27 +00:00
|
|
|
assert hass.data[AXIS_DOMAIN] == {}
|
2019-03-24 15:16:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_new_event_sends_signal(hass):
|
|
|
|
"""Make sure that new event send signal."""
|
|
|
|
entry = Mock()
|
|
|
|
entry.data = ENTRY_CONFIG
|
|
|
|
|
2020-01-02 23:02:59 +00:00
|
|
|
axis_device = axis.device.AxisNetworkDevice(hass, entry)
|
2019-03-24 15:16:50 +00:00
|
|
|
|
2020-01-02 23:02:59 +00:00
|
|
|
with patch.object(axis.device, "async_dispatcher_send") as mock_dispatch_send:
|
2020-05-14 08:49:27 +00:00
|
|
|
axis_device.async_event_callback(action=OPERATION_INITIALIZED, event_id="event")
|
2019-03-24 15:16:50 +00:00
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert len(mock_dispatch_send.mock_calls) == 1
|
|
|
|
assert len(mock_dispatch_send.mock_calls[0]) == 3
|
|
|
|
|
|
|
|
|
|
|
|
async def test_shutdown():
|
|
|
|
"""Successful shutdown."""
|
|
|
|
hass = Mock()
|
|
|
|
entry = Mock()
|
|
|
|
entry.data = ENTRY_CONFIG
|
|
|
|
|
2020-01-02 23:02:59 +00:00
|
|
|
axis_device = axis.device.AxisNetworkDevice(hass, entry)
|
2019-03-24 15:16:50 +00:00
|
|
|
axis_device.api = Mock()
|
|
|
|
|
|
|
|
axis_device.shutdown(None)
|
|
|
|
|
|
|
|
assert len(axis_device.api.stop.mock_calls) == 1
|
|
|
|
|
|
|
|
|
|
|
|
async def test_get_device_fails(hass):
|
|
|
|
"""Device unauthorized yields authentication required error."""
|
2019-07-31 19:25:30 +00:00
|
|
|
with patch(
|
2020-01-02 23:02:59 +00:00
|
|
|
"axis.param_cgi.Params.update_brand", side_effect=axislib.Unauthorized
|
|
|
|
), pytest.raises(axis.errors.AuthenticationRequired):
|
2020-01-30 21:20:30 +00:00
|
|
|
await axis.device.get_device(hass, host="", port="", username="", password="")
|
2019-03-24 15:16:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_get_device_device_unavailable(hass):
|
|
|
|
"""Device unavailable yields cannot connect error."""
|
2019-07-31 19:25:30 +00:00
|
|
|
with patch(
|
2020-01-02 23:02:59 +00:00
|
|
|
"axis.param_cgi.Params.update_brand", side_effect=axislib.RequestError
|
|
|
|
), pytest.raises(axis.errors.CannotConnect):
|
2020-01-30 21:20:30 +00:00
|
|
|
await axis.device.get_device(hass, host="", port="", username="", password="")
|
2019-03-24 15:16:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_get_device_unknown_error(hass):
|
|
|
|
"""Device yield unknown error."""
|
2019-07-31 19:25:30 +00:00
|
|
|
with patch(
|
2020-01-02 23:02:59 +00:00
|
|
|
"axis.param_cgi.Params.update_brand", side_effect=axislib.AxisException
|
|
|
|
), pytest.raises(axis.errors.AuthenticationRequired):
|
2020-01-30 21:20:30 +00:00
|
|
|
await axis.device.get_device(hass, host="", port="", username="", password="")
|