Increase test coverage of UniFi integration (#46347)

* Increase coverage of init

* Increase coverage of config_flow

* Improve coverage of controller

* Minor improvement to switch test

* Fix review comment

* Mock websocket class

* Replace the rest of the old websocket event tests

* Improve websocket fixture for cleaner tests

* Fix typing

* Improve connection state signalling based on Martins feedback

* Improve tests of reconnection_mechanisms based on Martins review comments

* Fix unload entry

* Fix isort issue after rebase

* Fix martins comment on not using caplog

* Fix wireless clients test

* Fix martins comments on wireless clients test
This commit is contained in:
Robert Svensson 2021-03-05 21:28:41 +01:00 committed by GitHub
parent 7c08592b5a
commit 793929f2ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 499 additions and 180 deletions

View file

@ -123,8 +123,9 @@ class UnifiFlowHandler(config_entries.ConfigFlow, domain=UNIFI_DOMAIN):
return await self.async_step_site() return await self.async_step_site()
host = self.config.get(CONF_HOST) if not (host := self.config.get(CONF_HOST, "")) and await async_discover_unifi(
if not host and await async_discover_unifi(self.hass): self.hass
):
host = "unifi" host = "unifi"
data = self.reauth_schema or { data = self.reauth_schema or {

View file

@ -415,9 +415,8 @@ class UniFiController:
If config entry is updated due to reauth flow If config entry is updated due to reauth flow
the entry might already have been reset and thus is not available. the entry might already have been reset and thus is not available.
""" """
if config_entry.entry_id not in hass.data[UNIFI_DOMAIN]: if not (controller := hass.data[UNIFI_DOMAIN].get(config_entry.entry_id)):
return return
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
controller.load_config_entry_options() controller.load_config_entry_options()
async_dispatcher_send(hass, controller.signal_options_update) async_dispatcher_send(hass, controller.signal_options_update)

View file

@ -1,9 +1,30 @@
"""Fixtures for UniFi methods.""" """Fixtures for UniFi methods."""
from typing import Optional
from unittest.mock import patch from unittest.mock import patch
from aiounifi.websocket import SIGNAL_CONNECTION_STATE, SIGNAL_DATA
import pytest import pytest
@pytest.fixture(autouse=True)
def mock_unifi_websocket():
"""No real websocket allowed."""
with patch("aiounifi.controller.WSClient") as mock:
def make_websocket_call(data: Optional[dict] = None, state: str = ""):
"""Generate a websocket call."""
if data:
mock.return_value.data = data
mock.call_args[1]["callback"](SIGNAL_DATA)
elif state:
mock.return_value.state = state
mock.call_args[1]["callback"](SIGNAL_CONNECTION_STATE)
else:
raise NotImplementedError
yield make_websocket_call
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def mock_discovery(): def mock_discovery():
"""No real network traffic allowed.""" """No real network traffic allowed."""

View file

@ -1,9 +1,12 @@
"""Test UniFi config flow.""" """Test UniFi config flow."""
import socket
from unittest.mock import patch from unittest.mock import patch
import aiounifi import aiounifi
from homeassistant import config_entries, data_entry_flow, setup from homeassistant import config_entries, data_entry_flow, setup
from homeassistant.components.unifi.config_flow import async_discover_unifi
from homeassistant.components.unifi.const import ( from homeassistant.components.unifi.const import (
CONF_ALLOW_BANDWIDTH_SENSORS, CONF_ALLOW_BANDWIDTH_SENSORS,
CONF_ALLOW_UPTIME_SENSORS, CONF_ALLOW_UPTIME_SENSORS,
@ -151,6 +154,23 @@ async def test_flow_works(hass, aioclient_mock, mock_discovery):
} }
async def test_flow_works_negative_discovery(hass, aioclient_mock, mock_discovery):
"""Test config flow with a negative outcome of async_discovery_unifi."""
result = await hass.config_entries.flow.async_init(
UNIFI_DOMAIN, context={"source": "user"}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"
assert result["data_schema"]({CONF_USERNAME: "", CONF_PASSWORD: ""}) == {
CONF_HOST: "",
CONF_USERNAME: "",
CONF_PASSWORD: "",
CONF_PORT: 443,
CONF_VERIFY_SSL: False,
}
async def test_flow_multiple_sites(hass, aioclient_mock): async def test_flow_multiple_sites(hass, aioclient_mock):
"""Test config flow works when finding multiple sites.""" """Test config flow works when finding multiple sites."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -617,3 +637,15 @@ async def test_form_ssdp_gets_form_with_ignored_entry(hass):
"host": "1.2.3.4", "host": "1.2.3.4",
"site": "default", "site": "default",
} }
async def test_discover_unifi_positive(hass):
"""Verify positive run of UniFi discovery."""
with patch("socket.gethostbyname", return_value=True):
assert await async_discover_unifi(hass)
async def test_discover_unifi_negative(hass):
"""Verify negative run of UniFi discovery."""
with patch("socket.gethostbyname", side_effect=socket.gaierror):
assert await async_discover_unifi(hass) is None

View file

@ -1,10 +1,12 @@
"""Test UniFi Controller.""" """Test UniFi Controller."""
import asyncio
from copy import deepcopy from copy import deepcopy
from datetime import timedelta from datetime import timedelta
from unittest.mock import patch from unittest.mock import Mock, patch
import aiounifi import aiounifi
from aiounifi.websocket import STATE_DISCONNECTED, STATE_RUNNING
import pytest import pytest
from homeassistant.components.device_tracker import DOMAIN as TRACKER_DOMAIN from homeassistant.components.device_tracker import DOMAIN as TRACKER_DOMAIN
@ -13,6 +15,8 @@ from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.components.unifi.const import ( from homeassistant.components.unifi.const import (
CONF_CONTROLLER, CONF_CONTROLLER,
CONF_SITE_ID, CONF_SITE_ID,
CONF_TRACK_CLIENTS,
CONF_TRACK_DEVICES,
DEFAULT_ALLOW_BANDWIDTH_SENSORS, DEFAULT_ALLOW_BANDWIDTH_SENSORS,
DEFAULT_ALLOW_UPTIME_SENSORS, DEFAULT_ALLOW_UPTIME_SENSORS,
DEFAULT_DETECTION_TIME, DEFAULT_DETECTION_TIME,
@ -22,7 +26,11 @@ from homeassistant.components.unifi.const import (
DOMAIN as UNIFI_DOMAIN, DOMAIN as UNIFI_DOMAIN,
UNIFI_WIRELESS_CLIENTS, UNIFI_WIRELESS_CLIENTS,
) )
from homeassistant.components.unifi.controller import PLATFORMS, get_controller from homeassistant.components.unifi.controller import (
PLATFORMS,
RETRY_TIMER,
get_controller,
)
from homeassistant.components.unifi.errors import AuthenticationRequired, CannotConnect from homeassistant.components.unifi.errors import AuthenticationRequired, CannotConnect
from homeassistant.const import ( from homeassistant.const import (
CONF_HOST, CONF_HOST,
@ -32,10 +40,13 @@ from homeassistant.const import (
CONF_VERIFY_SSL, CONF_VERIFY_SSL,
CONTENT_TYPE_JSON, CONTENT_TYPE_JSON,
) )
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, async_fire_time_changed
DEFAULT_CONFIG_ENTRY_ID = 1
DEFAULT_HOST = "1.2.3.4" DEFAULT_HOST = "1.2.3.4"
DEFAULT_SITE = "site_id" DEFAULT_SITE = "site_id"
@ -154,6 +165,7 @@ async def setup_unifi_integration(
wlans_response=None, wlans_response=None,
known_wireless_clients=None, known_wireless_clients=None,
controllers=None, controllers=None,
unique_id="1",
): ):
"""Create the UniFi controller.""" """Create the UniFi controller."""
assert await async_setup_component(hass, UNIFI_DOMAIN, {}) assert await async_setup_component(hass, UNIFI_DOMAIN, {})
@ -162,8 +174,8 @@ async def setup_unifi_integration(
domain=UNIFI_DOMAIN, domain=UNIFI_DOMAIN,
data=deepcopy(config), data=deepcopy(config),
options=deepcopy(options), options=deepcopy(options),
entry_id=1, unique_id=unique_id,
unique_id="1", entry_id=DEFAULT_CONFIG_ENTRY_ID,
version=1, version=1,
) )
config_entry.add_to_hass(hass) config_entry.add_to_hass(hass)
@ -188,8 +200,7 @@ async def setup_unifi_integration(
wlans_response=wlans_response, wlans_response=wlans_response,
) )
with patch.object(aiounifi.websocket.WSClient, "start", return_value=True): await hass.config_entries.async_setup(config_entry.entry_id)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
if config_entry.entry_id not in hass.data[UNIFI_DOMAIN]: if config_entry.entry_id not in hass.data[UNIFI_DOMAIN]:
@ -276,6 +287,27 @@ async def test_controller_unknown_error(hass):
assert hass.data[UNIFI_DOMAIN] == {} assert hass.data[UNIFI_DOMAIN] == {}
async def test_config_entry_updated(hass, aioclient_mock):
"""Calling reset when the entry has been setup."""
config_entry = await setup_unifi_integration(hass, aioclient_mock)
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
event_call = Mock()
unsub = async_dispatcher_connect(hass, controller.signal_options_update, event_call)
hass.config_entries.async_update_entry(
config_entry, options={CONF_TRACK_CLIENTS: False, CONF_TRACK_DEVICES: False}
)
await hass.async_block_till_done()
assert config_entry.options[CONF_TRACK_CLIENTS] is False
assert config_entry.options[CONF_TRACK_DEVICES] is False
event_call.assert_called_once()
unsub()
async def test_reset_after_successful_setup(hass, aioclient_mock): async def test_reset_after_successful_setup(hass, aioclient_mock):
"""Calling reset when the entry has been setup.""" """Calling reset when the entry has been setup."""
config_entry = await setup_unifi_integration(hass, aioclient_mock) config_entry = await setup_unifi_integration(hass, aioclient_mock)
@ -290,33 +322,126 @@ async def test_reset_after_successful_setup(hass, aioclient_mock):
assert len(controller.listeners) == 0 assert len(controller.listeners) == 0
async def test_wireless_client_event_calls_update_wireless_devices( async def test_reset_fails(hass, aioclient_mock):
hass, aioclient_mock """Calling reset when the entry has been setup can return false."""
):
"""Call update_wireless_devices method when receiving wireless client event."""
config_entry = await setup_unifi_integration(hass, aioclient_mock) config_entry = await setup_unifi_integration(hass, aioclient_mock)
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id] controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
with patch(
"homeassistant.config_entries.ConfigEntries.async_forward_entry_unload",
return_value=False,
):
result = await controller.async_reset()
await hass.async_block_till_done()
assert result is False
async def test_connection_state_signalling(hass, aioclient_mock, mock_unifi_websocket):
"""Verify connection statesignalling and connection state are working."""
client = {
"hostname": "client",
"ip": "10.0.0.1",
"is_wired": True,
"last_seen": dt_util.as_timestamp(dt_util.utcnow()),
"mac": "00:00:00:00:00:01",
}
await setup_unifi_integration(hass, aioclient_mock, clients_response=[client])
# Controller is connected
assert hass.states.get("device_tracker.client").state == "home"
mock_unifi_websocket(state=STATE_DISCONNECTED)
await hass.async_block_till_done()
# Controller is disconnected
assert hass.states.get("device_tracker.client").state == "unavailable"
mock_unifi_websocket(state=STATE_RUNNING)
await hass.async_block_till_done()
# Controller is once again connected
assert hass.states.get("device_tracker.client").state == "home"
async def test_wireless_client_event_calls_update_wireless_devices(
hass, aioclient_mock, mock_unifi_websocket
):
"""Call update_wireless_devices method when receiving wireless client event."""
await setup_unifi_integration(hass, aioclient_mock)
with patch( with patch(
"homeassistant.components.unifi.controller.UniFiController.update_wireless_clients", "homeassistant.components.unifi.controller.UniFiController.update_wireless_clients",
return_value=None, return_value=None,
) as wireless_clients_mock: ) as wireless_clients_mock:
controller.api.websocket._data = { mock_unifi_websocket(
"meta": {"rc": "ok", "message": "events"}, data={
"data": [ "meta": {"rc": "ok", "message": "events"},
{ "data": [
"datetime": "2020-01-20T19:37:04Z", {
"key": aiounifi.events.WIRELESS_CLIENT_CONNECTED, "datetime": "2020-01-20T19:37:04Z",
"msg": "User[11:22:33:44:55:66] has connected to WLAN", "key": aiounifi.events.WIRELESS_CLIENT_CONNECTED,
"time": 1579549024893, "msg": "User[11:22:33:44:55:66] has connected to WLAN",
} "time": 1579549024893,
], }
} ],
controller.api.session_handler("data") },
)
assert wireless_clients_mock.assert_called_once assert wireless_clients_mock.assert_called_once
async def test_reconnect_mechanism(hass, aioclient_mock, mock_unifi_websocket):
"""Verify reconnect prints only on first reconnection try."""
await setup_unifi_integration(hass, aioclient_mock)
aioclient_mock.clear_requests()
aioclient_mock.post(f"https://{DEFAULT_HOST}:1234/api/login", status=502)
mock_unifi_websocket(state=STATE_DISCONNECTED)
await hass.async_block_till_done()
assert aioclient_mock.call_count == 0
new_time = dt_util.utcnow() + timedelta(seconds=RETRY_TIMER)
async_fire_time_changed(hass, new_time)
await hass.async_block_till_done()
assert aioclient_mock.call_count == 1
new_time = dt_util.utcnow() + timedelta(seconds=RETRY_TIMER)
async_fire_time_changed(hass, new_time)
await hass.async_block_till_done()
assert aioclient_mock.call_count == 2
@pytest.mark.parametrize(
"exception",
[
asyncio.TimeoutError,
aiounifi.BadGateway,
aiounifi.ServiceUnavailable,
aiounifi.AiounifiException,
],
)
async def test_reconnect_mechanism_exceptions(
hass, aioclient_mock, mock_unifi_websocket, exception
):
"""Verify async_reconnect calls expected methods."""
await setup_unifi_integration(hass, aioclient_mock)
with patch("aiounifi.Controller.login", side_effect=exception), patch(
"homeassistant.components.unifi.controller.UniFiController.reconnect"
) as mock_reconnect:
mock_unifi_websocket(state=STATE_DISCONNECTED)
await hass.async_block_till_done()
new_time = dt_util.utcnow() + timedelta(seconds=RETRY_TIMER)
async_fire_time_changed(hass, new_time)
mock_reconnect.assert_called_once()
async def test_get_controller(hass): async def test_get_controller(hass):
"""Successful call.""" """Successful call."""
with patch("aiounifi.Controller.check_unifi_os", return_value=True), patch( with patch("aiounifi.Controller.check_unifi_os", return_value=True), patch(

View file

@ -8,9 +8,8 @@ from aiounifi.controller import (
MESSAGE_CLIENT_REMOVED, MESSAGE_CLIENT_REMOVED,
MESSAGE_DEVICE, MESSAGE_DEVICE,
MESSAGE_EVENT, MESSAGE_EVENT,
SIGNAL_CONNECTION_STATE,
) )
from aiounifi.websocket import SIGNAL_DATA, STATE_DISCONNECTED, STATE_RUNNING from aiounifi.websocket import STATE_DISCONNECTED, STATE_RUNNING
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.device_tracker import DOMAIN as TRACKER_DOMAIN from homeassistant.components.device_tracker import DOMAIN as TRACKER_DOMAIN
@ -157,7 +156,7 @@ async def test_no_clients(hass, aioclient_mock):
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 0 assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 0
async def test_tracked_wireless_clients(hass, aioclient_mock): async def test_tracked_wireless_clients(hass, aioclient_mock, mock_unifi_websocket):
"""Test the update_items function with some clients.""" """Test the update_items function with some clients."""
config_entry = await setup_unifi_integration( config_entry = await setup_unifi_integration(
hass, aioclient_mock, clients_response=[CLIENT_1] hass, aioclient_mock, clients_response=[CLIENT_1]
@ -171,11 +170,12 @@ async def test_tracked_wireless_clients(hass, aioclient_mock):
# State change signalling works without events # State change signalling works without events
client_1_copy = copy(CLIENT_1) client_1_copy = copy(CLIENT_1)
controller.api.websocket._data = { mock_unifi_websocket(
"meta": {"message": MESSAGE_CLIENT}, data={
"data": [client_1_copy], "meta": {"message": MESSAGE_CLIENT},
} "data": [client_1_copy],
controller.api.session_handler(SIGNAL_DATA) }
)
await hass.async_block_till_done() await hass.async_block_till_done()
client_1 = hass.states.get("device_tracker.client_1") client_1 = hass.states.get("device_tracker.client_1")
@ -186,11 +186,13 @@ async def test_tracked_wireless_clients(hass, aioclient_mock):
assert client_1.attributes["host_name"] == "client_1" assert client_1.attributes["host_name"] == "client_1"
# State change signalling works with events # State change signalling works with events
controller.api.websocket._data = {
"meta": {"message": MESSAGE_EVENT}, mock_unifi_websocket(
"data": [EVENT_CLIENT_1_WIRELESS_DISCONNECTED], data={
} "meta": {"message": MESSAGE_EVENT},
controller.api.session_handler(SIGNAL_DATA) "data": [EVENT_CLIENT_1_WIRELESS_DISCONNECTED],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
client_1 = hass.states.get("device_tracker.client_1") client_1 = hass.states.get("device_tracker.client_1")
@ -204,30 +206,30 @@ async def test_tracked_wireless_clients(hass, aioclient_mock):
client_1 = hass.states.get("device_tracker.client_1") client_1 = hass.states.get("device_tracker.client_1")
assert client_1.state == "not_home" assert client_1.state == "not_home"
controller.api.websocket._data = { mock_unifi_websocket(
"meta": {"message": MESSAGE_EVENT}, data={
"data": [EVENT_CLIENT_1_WIRELESS_CONNECTED], "meta": {"message": MESSAGE_EVENT},
} "data": [EVENT_CLIENT_1_WIRELESS_CONNECTED],
controller.api.session_handler(SIGNAL_DATA) }
)
await hass.async_block_till_done() await hass.async_block_till_done()
client_1 = hass.states.get("device_tracker.client_1") client_1 = hass.states.get("device_tracker.client_1")
assert client_1.state == "home" assert client_1.state == "home"
async def test_tracked_clients(hass, aioclient_mock): async def test_tracked_clients(hass, aioclient_mock, mock_unifi_websocket):
"""Test the update_items function with some clients.""" """Test the update_items function with some clients."""
client_4_copy = copy(CLIENT_4) client_4_copy = copy(CLIENT_4)
client_4_copy["last_seen"] = dt_util.as_timestamp(dt_util.utcnow()) client_4_copy["last_seen"] = dt_util.as_timestamp(dt_util.utcnow())
config_entry = await setup_unifi_integration( await setup_unifi_integration(
hass, hass,
aioclient_mock, aioclient_mock,
options={CONF_SSID_FILTER: ["ssid"]}, options={CONF_SSID_FILTER: ["ssid"]},
clients_response=[CLIENT_1, CLIENT_2, CLIENT_3, CLIENT_5, client_4_copy], clients_response=[CLIENT_1, CLIENT_2, CLIENT_3, CLIENT_5, client_4_copy],
known_wireless_clients=(CLIENT_4["mac"],), known_wireless_clients=(CLIENT_4["mac"],),
) )
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 4 assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 4
client_1 = hass.states.get("device_tracker.client_1") client_1 = hass.states.get("device_tracker.client_1")
@ -254,22 +256,26 @@ async def test_tracked_clients(hass, aioclient_mock):
# State change signalling works # State change signalling works
client_1_copy = copy(CLIENT_1) client_1_copy = copy(CLIENT_1)
event = {"meta": {"message": MESSAGE_CLIENT}, "data": [client_1_copy]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_CLIENT},
"data": [client_1_copy],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
client_1 = hass.states.get("device_tracker.client_1") client_1 = hass.states.get("device_tracker.client_1")
assert client_1.state == "home" assert client_1.state == "home"
async def test_tracked_devices(hass, aioclient_mock): async def test_tracked_devices(hass, aioclient_mock, mock_unifi_websocket):
"""Test the update_items function with some devices.""" """Test the update_items function with some devices."""
config_entry = await setup_unifi_integration( await setup_unifi_integration(
hass, hass,
aioclient_mock, aioclient_mock,
devices_response=[DEVICE_1, DEVICE_2], devices_response=[DEVICE_1, DEVICE_2],
) )
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 2 assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 2
device_1 = hass.states.get("device_tracker.device_1") device_1 = hass.states.get("device_tracker.device_1")
@ -283,12 +289,20 @@ async def test_tracked_devices(hass, aioclient_mock):
# State change signalling work # State change signalling work
device_1_copy = copy(DEVICE_1) device_1_copy = copy(DEVICE_1)
device_1_copy["next_interval"] = 20 device_1_copy["next_interval"] = 20
event = {"meta": {"message": MESSAGE_DEVICE}, "data": [device_1_copy]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_DEVICE},
"data": [device_1_copy],
}
)
device_2_copy = copy(DEVICE_2) device_2_copy = copy(DEVICE_2)
device_2_copy["next_interval"] = 50 device_2_copy["next_interval"] = 50
event = {"meta": {"message": MESSAGE_DEVICE}, "data": [device_2_copy]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_DEVICE},
"data": [device_2_copy],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
device_1 = hass.states.get("device_tracker.device_1") device_1 = hass.states.get("device_tracker.device_1")
@ -309,8 +323,12 @@ async def test_tracked_devices(hass, aioclient_mock):
# Disabled device is unavailable # Disabled device is unavailable
device_1_copy = copy(DEVICE_1) device_1_copy = copy(DEVICE_1)
device_1_copy["disabled"] = True device_1_copy["disabled"] = True
event = {"meta": {"message": MESSAGE_DEVICE}, "data": [device_1_copy]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_DEVICE},
"data": [device_1_copy],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
device_1 = hass.states.get("device_tracker.device_1") device_1 = hass.states.get("device_tracker.device_1")
@ -319,10 +337,18 @@ async def test_tracked_devices(hass, aioclient_mock):
# Update device registry when device is upgraded # Update device registry when device is upgraded
device_2_copy = copy(DEVICE_2) device_2_copy = copy(DEVICE_2)
device_2_copy["version"] = EVENT_DEVICE_2_UPGRADED["version_to"] device_2_copy["version"] = EVENT_DEVICE_2_UPGRADED["version_to"]
message = {"meta": {"message": MESSAGE_DEVICE}, "data": [device_2_copy]} mock_unifi_websocket(
controller.api.message_handler(message) data={
event = {"meta": {"message": MESSAGE_EVENT}, "data": [EVENT_DEVICE_2_UPGRADED]} "meta": {"message": MESSAGE_DEVICE},
controller.api.message_handler(event) "data": [device_2_copy],
}
)
mock_unifi_websocket(
data={
"meta": {"message": MESSAGE_EVENT},
"data": [EVENT_DEVICE_2_UPGRADED],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
# Verify device registry has been updated # Verify device registry has been updated
@ -333,12 +359,12 @@ async def test_tracked_devices(hass, aioclient_mock):
assert device.sw_version == EVENT_DEVICE_2_UPGRADED["version_to"] assert device.sw_version == EVENT_DEVICE_2_UPGRADED["version_to"]
async def test_remove_clients(hass, aioclient_mock): async def test_remove_clients(hass, aioclient_mock, mock_unifi_websocket):
"""Test the remove_items function with some clients.""" """Test the remove_items function with some clients."""
config_entry = await setup_unifi_integration( await setup_unifi_integration(
hass, aioclient_mock, clients_response=[CLIENT_1, CLIENT_2] hass, aioclient_mock, clients_response=[CLIENT_1, CLIENT_2]
) )
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 2 assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 2
client_1 = hass.states.get("device_tracker.client_1") client_1 = hass.states.get("device_tracker.client_1")
@ -347,11 +373,12 @@ async def test_remove_clients(hass, aioclient_mock):
wired_client = hass.states.get("device_tracker.wired_client") wired_client = hass.states.get("device_tracker.wired_client")
assert wired_client is not None assert wired_client is not None
controller.api.websocket._data = { mock_unifi_websocket(
"meta": {"message": MESSAGE_CLIENT_REMOVED}, data={
"data": [CLIENT_1], "meta": {"message": MESSAGE_CLIENT_REMOVED},
} "data": [CLIENT_1],
controller.api.session_handler(SIGNAL_DATA) }
)
await hass.async_block_till_done() await hass.async_block_till_done()
await hass.async_block_till_done() await hass.async_block_till_done()
@ -364,15 +391,15 @@ async def test_remove_clients(hass, aioclient_mock):
assert wired_client is not None assert wired_client is not None
async def test_controller_state_change(hass, aioclient_mock): async def test_controller_state_change(hass, aioclient_mock, mock_unifi_websocket):
"""Verify entities state reflect on controller becoming unavailable.""" """Verify entities state reflect on controller becoming unavailable."""
config_entry = await setup_unifi_integration( await setup_unifi_integration(
hass, hass,
aioclient_mock, aioclient_mock,
clients_response=[CLIENT_1], clients_response=[CLIENT_1],
devices_response=[DEVICE_1], devices_response=[DEVICE_1],
) )
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 2 assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 2
client_1 = hass.states.get("device_tracker.client_1") client_1 = hass.states.get("device_tracker.client_1")
@ -382,9 +409,7 @@ async def test_controller_state_change(hass, aioclient_mock):
assert device_1.state == "home" assert device_1.state == "home"
# Controller unavailable # Controller unavailable
controller.async_unifi_signalling_callback( mock_unifi_websocket(state=STATE_DISCONNECTED)
SIGNAL_CONNECTION_STATE, STATE_DISCONNECTED
)
await hass.async_block_till_done() await hass.async_block_till_done()
client_1 = hass.states.get("device_tracker.client_1") client_1 = hass.states.get("device_tracker.client_1")
@ -394,7 +419,7 @@ async def test_controller_state_change(hass, aioclient_mock):
assert device_1.state == STATE_UNAVAILABLE assert device_1.state == STATE_UNAVAILABLE
# Controller available # Controller available
controller.async_unifi_signalling_callback(SIGNAL_CONNECTION_STATE, STATE_RUNNING) mock_unifi_websocket(state=STATE_RUNNING)
await hass.async_block_till_done() await hass.async_block_till_done()
client_1 = hass.states.get("device_tracker.client_1") client_1 = hass.states.get("device_tracker.client_1")
@ -554,7 +579,7 @@ async def test_option_track_devices(hass, aioclient_mock):
assert device_1 is not None assert device_1 is not None
async def test_option_ssid_filter(hass, aioclient_mock): async def test_option_ssid_filter(hass, aioclient_mock, mock_unifi_websocket):
"""Test the SSID filter works. """Test the SSID filter works.
Client 1 will travel from a supported SSID to an unsupported ssid. Client 1 will travel from a supported SSID to an unsupported ssid.
@ -593,13 +618,21 @@ async def test_option_ssid_filter(hass, aioclient_mock):
# Roams to SSID outside of filter # Roams to SSID outside of filter
client_1_copy = copy(CLIENT_1) client_1_copy = copy(CLIENT_1)
client_1_copy["essid"] = "other_ssid" client_1_copy["essid"] = "other_ssid"
event = {"meta": {"message": MESSAGE_CLIENT}, "data": [client_1_copy]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_CLIENT},
"data": [client_1_copy],
}
)
# Data update while SSID filter is in effect shouldn't create the client # Data update while SSID filter is in effect shouldn't create the client
client_3_copy = copy(CLIENT_3) client_3_copy = copy(CLIENT_3)
client_3_copy["last_seen"] = dt_util.as_timestamp(dt_util.utcnow()) client_3_copy["last_seen"] = dt_util.as_timestamp(dt_util.utcnow())
event = {"meta": {"message": MESSAGE_CLIENT}, "data": [client_3_copy]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_CLIENT},
"data": [client_3_copy],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
# SSID filter marks client as away # SSID filter marks client as away
@ -616,10 +649,19 @@ async def test_option_ssid_filter(hass, aioclient_mock):
options={CONF_SSID_FILTER: []}, options={CONF_SSID_FILTER: []},
) )
await hass.async_block_till_done() await hass.async_block_till_done()
event = {"meta": {"message": MESSAGE_CLIENT}, "data": [client_1_copy]}
controller.api.message_handler(event) mock_unifi_websocket(
event = {"meta": {"message": MESSAGE_CLIENT}, "data": [client_3_copy]} data={
controller.api.message_handler(event) "meta": {"message": MESSAGE_CLIENT},
"data": [client_1_copy],
}
)
mock_unifi_websocket(
data={
"meta": {"message": MESSAGE_CLIENT},
"data": [client_3_copy],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
client_1 = hass.states.get("device_tracker.client_1") client_1 = hass.states.get("device_tracker.client_1")
@ -636,16 +678,24 @@ async def test_option_ssid_filter(hass, aioclient_mock):
client_1 = hass.states.get("device_tracker.client_1") client_1 = hass.states.get("device_tracker.client_1")
assert client_1.state == "not_home" assert client_1.state == "not_home"
event = {"meta": {"message": MESSAGE_CLIENT}, "data": [client_3_copy]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_CLIENT},
"data": [client_3_copy],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
# Client won't go away until after next update # Client won't go away until after next update
client_3 = hass.states.get("device_tracker.client_3") client_3 = hass.states.get("device_tracker.client_3")
assert client_3.state == "home" assert client_3.state == "home"
# Trigger update to get client marked as away # Trigger update to get client marked as away
event = {"meta": {"message": MESSAGE_CLIENT}, "data": [CLIENT_3]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_CLIENT},
"data": [client_3_copy],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
new_time = ( new_time = (
@ -659,7 +709,9 @@ async def test_option_ssid_filter(hass, aioclient_mock):
assert client_3.state == "not_home" assert client_3.state == "not_home"
async def test_wireless_client_go_wired_issue(hass, aioclient_mock): async def test_wireless_client_go_wired_issue(
hass, aioclient_mock, mock_unifi_websocket
):
"""Test the solution to catch wireless device go wired UniFi issue. """Test the solution to catch wireless device go wired UniFi issue.
UniFi has a known issue that when a wireless device goes away it sometimes gets marked as wired. UniFi has a known issue that when a wireless device goes away it sometimes gets marked as wired.
@ -681,8 +733,12 @@ async def test_wireless_client_go_wired_issue(hass, aioclient_mock):
# Trigger wired bug # Trigger wired bug
client_1_client["is_wired"] = True client_1_client["is_wired"] = True
event = {"meta": {"message": MESSAGE_CLIENT}, "data": [client_1_client]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_CLIENT},
"data": [client_1_client],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
# Wired bug fix keeps client marked as wireless # Wired bug fix keeps client marked as wireless
@ -702,8 +758,12 @@ async def test_wireless_client_go_wired_issue(hass, aioclient_mock):
assert client_1.attributes["is_wired"] is False assert client_1.attributes["is_wired"] is False
# Try to mark client as connected # Try to mark client as connected
event = {"meta": {"message": MESSAGE_CLIENT}, "data": [client_1_client]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_CLIENT},
"data": [client_1_client],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
# Make sure it don't go online again until wired bug disappears # Make sure it don't go online again until wired bug disappears
@ -713,8 +773,12 @@ async def test_wireless_client_go_wired_issue(hass, aioclient_mock):
# Make client wireless # Make client wireless
client_1_client["is_wired"] = False client_1_client["is_wired"] = False
event = {"meta": {"message": MESSAGE_CLIENT}, "data": [client_1_client]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_CLIENT},
"data": [client_1_client],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
# Client is no longer affected by wired bug and can be marked online # Client is no longer affected by wired bug and can be marked online
@ -723,7 +787,7 @@ async def test_wireless_client_go_wired_issue(hass, aioclient_mock):
assert client_1.attributes["is_wired"] is False assert client_1.attributes["is_wired"] is False
async def test_option_ignore_wired_bug(hass, aioclient_mock): async def test_option_ignore_wired_bug(hass, aioclient_mock, mock_unifi_websocket):
"""Test option to ignore wired bug.""" """Test option to ignore wired bug."""
client_1_client = copy(CLIENT_1) client_1_client = copy(CLIENT_1)
client_1_client["last_seen"] = dt_util.as_timestamp(dt_util.utcnow()) client_1_client["last_seen"] = dt_util.as_timestamp(dt_util.utcnow())
@ -745,8 +809,12 @@ async def test_option_ignore_wired_bug(hass, aioclient_mock):
# Trigger wired bug # Trigger wired bug
client_1_client["is_wired"] = True client_1_client["is_wired"] = True
event = {"meta": {"message": MESSAGE_CLIENT}, "data": [client_1_client]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_CLIENT},
"data": [client_1_client],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
# Wired bug in effect # Wired bug in effect
@ -766,8 +834,12 @@ async def test_option_ignore_wired_bug(hass, aioclient_mock):
assert client_1.attributes["is_wired"] is True assert client_1.attributes["is_wired"] is True
# Mark client as connected again # Mark client as connected again
event = {"meta": {"message": MESSAGE_CLIENT}, "data": [client_1_client]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_CLIENT},
"data": [client_1_client],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
# Ignoring wired bug allows client to go home again even while affected # Ignoring wired bug allows client to go home again even while affected
@ -777,8 +849,12 @@ async def test_option_ignore_wired_bug(hass, aioclient_mock):
# Make client wireless # Make client wireless
client_1_client["is_wired"] = False client_1_client["is_wired"] = False
event = {"meta": {"message": MESSAGE_CLIENT}, "data": [client_1_client]} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_CLIENT},
"data": [client_1_client],
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
# Client is wireless and still connected # Client is wireless and still connected

View file

@ -1,14 +1,20 @@
"""Test UniFi setup process.""" """Test UniFi setup process."""
from unittest.mock import AsyncMock, Mock, patch from unittest.mock import AsyncMock, patch
from homeassistant.components import unifi from homeassistant.components import unifi
from homeassistant.components.unifi import async_flatten_entry_data from homeassistant.components.unifi import async_flatten_entry_data
from homeassistant.components.unifi.const import CONF_CONTROLLER, DOMAIN as UNIFI_DOMAIN from homeassistant.components.unifi.const import CONF_CONTROLLER, DOMAIN as UNIFI_DOMAIN
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from .test_controller import CONTROLLER_DATA, ENTRY_CONFIG, setup_unifi_integration from .test_controller import (
CONTROLLER_DATA,
DEFAULT_CONFIG_ENTRY_ID,
ENTRY_CONFIG,
setup_unifi_integration,
)
from tests.common import MockConfigEntry, mock_coro from tests.common import MockConfigEntry
async def test_setup_with_no_config(hass): async def test_setup_with_no_config(hass):
@ -19,7 +25,7 @@ async def test_setup_with_no_config(hass):
async def test_successful_config_entry(hass, aioclient_mock): async def test_successful_config_entry(hass, aioclient_mock):
"""Test that configured options for a host are loaded via config entry.""" """Test that configured options for a host are loaded via config entry."""
await setup_unifi_integration(hass, aioclient_mock) await setup_unifi_integration(hass, aioclient_mock, unique_id=None)
assert hass.data[UNIFI_DOMAIN] assert hass.data[UNIFI_DOMAIN]
@ -32,29 +38,28 @@ async def test_controller_fail_setup(hass):
assert hass.data[UNIFI_DOMAIN] == {} assert hass.data[UNIFI_DOMAIN] == {}
async def test_controller_no_mac(hass): async def test_controller_mac(hass):
"""Test that configured options for a host are loaded via config entry.""" """Test that configured options for a host are loaded via config entry."""
entry = MockConfigEntry( entry = MockConfigEntry(
domain=UNIFI_DOMAIN, domain=UNIFI_DOMAIN, data=ENTRY_CONFIG, unique_id="1", entry_id=1
data=ENTRY_CONFIG,
unique_id="1",
version=1,
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
mock_registry = Mock()
with patch( with patch("homeassistant.components.unifi.UniFiController") as mock_controller:
"homeassistant.components.unifi.UniFiController"
) as mock_controller, patch(
"homeassistant.helpers.device_registry.async_get_registry",
return_value=mock_coro(mock_registry),
):
mock_controller.return_value.async_setup = AsyncMock(return_value=True) mock_controller.return_value.async_setup = AsyncMock(return_value=True)
mock_controller.return_value.mac = None mock_controller.return_value.mac = "mac1"
assert await unifi.async_setup_entry(hass, entry) is True assert await unifi.async_setup_entry(hass, entry) is True
assert len(mock_controller.mock_calls) == 2 assert len(mock_controller.mock_calls) == 2
assert len(mock_registry.mock_calls) == 0 device_registry = await hass.helpers.device_registry.async_get_registry()
device = device_registry.async_get_or_create(
config_entry_id=entry.entry_id, connections={(CONNECTION_NETWORK_MAC, "mac1")}
)
assert device.manufacturer == "Ubiquiti Networks"
assert device.model == "UniFi Controller"
assert device.name == "UniFi Controller"
assert device.sw_version is None
async def test_flatten_entry_data(hass): async def test_flatten_entry_data(hass):
@ -73,5 +78,45 @@ async def test_unload_entry(hass, aioclient_mock):
config_entry = await setup_unifi_integration(hass, aioclient_mock) config_entry = await setup_unifi_integration(hass, aioclient_mock)
assert hass.data[UNIFI_DOMAIN] assert hass.data[UNIFI_DOMAIN]
assert await unifi.async_unload_entry(hass, config_entry) assert await hass.config_entries.async_unload(config_entry.entry_id)
assert not hass.data[UNIFI_DOMAIN] assert not hass.data[UNIFI_DOMAIN]
async def test_wireless_clients(hass, hass_storage, aioclient_mock):
"""Verify wireless clients class."""
hass_storage[unifi.STORAGE_KEY] = {
"version": unifi.STORAGE_VERSION,
"data": {
DEFAULT_CONFIG_ENTRY_ID: {
"wireless_devices": ["00:00:00:00:00:00", "00:00:00:00:00:01"]
}
},
}
client_1 = {
"hostname": "client_1",
"ip": "10.0.0.1",
"is_wired": False,
"mac": "00:00:00:00:00:01",
}
client_2 = {
"hostname": "client_2",
"ip": "10.0.0.2",
"is_wired": False,
"mac": "00:00:00:00:00:02",
}
config_entry = await setup_unifi_integration(
hass, aioclient_mock, clients_response=[client_1, client_2]
)
for mac in [
"00:00:00:00:00:00",
"00:00:00:00:00:01",
"00:00:00:00:00:02",
]:
assert (
mac
in hass_storage[unifi.STORAGE_KEY]["data"][config_entry.entry_id][
"wireless_devices"
]
)

View file

@ -2,7 +2,6 @@
from copy import deepcopy from copy import deepcopy
from aiounifi.controller import MESSAGE_CLIENT, MESSAGE_CLIENT_REMOVED from aiounifi.controller import MESSAGE_CLIENT, MESSAGE_CLIENT_REMOVED
from aiounifi.websocket import SIGNAL_DATA
from homeassistant.components.device_tracker import DOMAIN as TRACKER_DOMAIN from homeassistant.components.device_tracker import DOMAIN as TRACKER_DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
@ -63,7 +62,7 @@ async def test_no_clients(hass, aioclient_mock):
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 0 assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 0
async def test_sensors(hass, aioclient_mock): async def test_sensors(hass, aioclient_mock, mock_unifi_websocket):
"""Test the update_items function with some clients.""" """Test the update_items function with some clients."""
config_entry = await setup_unifi_integration( config_entry = await setup_unifi_integration(
hass, hass,
@ -104,8 +103,12 @@ async def test_sensors(hass, aioclient_mock):
clients[1]["tx_bytes"] = 6789000000 clients[1]["tx_bytes"] = 6789000000
clients[1]["uptime"] = 1600180860 clients[1]["uptime"] = 1600180860
event = {"meta": {"message": MESSAGE_CLIENT}, "data": clients} mock_unifi_websocket(
controller.api.message_handler(event) data={
"meta": {"message": MESSAGE_CLIENT},
"data": clients,
}
)
await hass.async_block_till_done() await hass.async_block_till_done()
wireless_client_rx = hass.states.get("sensor.wireless_client_name_rx") wireless_client_rx = hass.states.get("sensor.wireless_client_name_rx")
@ -178,9 +181,9 @@ async def test_sensors(hass, aioclient_mock):
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 6 assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 6
async def test_remove_sensors(hass, aioclient_mock): async def test_remove_sensors(hass, aioclient_mock, mock_unifi_websocket):
"""Test the remove_items function with some clients.""" """Test the remove_items function with some clients."""
config_entry = await setup_unifi_integration( await setup_unifi_integration(
hass, hass,
aioclient_mock, aioclient_mock,
options={ options={
@ -189,7 +192,7 @@ async def test_remove_sensors(hass, aioclient_mock):
}, },
clients_response=CLIENTS, clients_response=CLIENTS,
) )
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 6 assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 6
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 2 assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 2
@ -209,11 +212,12 @@ async def test_remove_sensors(hass, aioclient_mock):
wireless_client_uptime = hass.states.get("sensor.wireless_client_name_uptime") wireless_client_uptime = hass.states.get("sensor.wireless_client_name_uptime")
assert wireless_client_uptime is not None assert wireless_client_uptime is not None
controller.api.websocket._data = { mock_unifi_websocket(
"meta": {"message": MESSAGE_CLIENT_REMOVED}, data={
"data": [CLIENTS[0]], "meta": {"message": MESSAGE_CLIENT_REMOVED},
} "data": [CLIENTS[0]],
controller.api.session_handler(SIGNAL_DATA) }
)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 3 assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 3

View file

@ -2,7 +2,6 @@
from copy import deepcopy from copy import deepcopy
from aiounifi.controller import MESSAGE_CLIENT_REMOVED, MESSAGE_EVENT from aiounifi.controller import MESSAGE_CLIENT_REMOVED, MESSAGE_EVENT
from aiounifi.websocket import SIGNAL_DATA
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.device_tracker import DOMAIN as TRACKER_DOMAIN from homeassistant.components.device_tracker import DOMAIN as TRACKER_DOMAIN
@ -17,6 +16,7 @@ from homeassistant.components.unifi.const import (
) )
from homeassistant.components.unifi.switch import POE_SWITCH from homeassistant.components.unifi.switch import POE_SWITCH
from homeassistant.helpers import entity_registry from homeassistant.helpers import entity_registry
from homeassistant.helpers.dispatcher import async_dispatcher_send
from .test_controller import ( from .test_controller import (
CONTROLLER_HOST, CONTROLLER_HOST,
@ -370,6 +370,7 @@ async def test_switches(hass, aioclient_mock):
dpi_switch = hass.states.get("switch.block_media_streaming") dpi_switch = hass.states.get("switch.block_media_streaming")
assert dpi_switch is not None assert dpi_switch is not None
assert dpi_switch.state == "on" assert dpi_switch.state == "on"
assert dpi_switch.attributes["icon"] == "mdi:network"
# Block and unblock client # Block and unblock client
@ -419,17 +420,22 @@ async def test_switches(hass, aioclient_mock):
assert aioclient_mock.call_count == 14 assert aioclient_mock.call_count == 14
assert aioclient_mock.mock_calls[13][2] == {"enabled": True} assert aioclient_mock.mock_calls[13][2] == {"enabled": True}
# Make sure no duplicates arise on generic signal update
async_dispatcher_send(hass, controller.signal_update)
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 4
async def test_remove_switches(hass, aioclient_mock):
async def test_remove_switches(hass, aioclient_mock, mock_unifi_websocket):
"""Test the update_items function with some clients.""" """Test the update_items function with some clients."""
config_entry = await setup_unifi_integration( await setup_unifi_integration(
hass, hass,
aioclient_mock, aioclient_mock,
options={CONF_BLOCK_CLIENT: [UNBLOCKED["mac"]]}, options={CONF_BLOCK_CLIENT: [UNBLOCKED["mac"]]},
clients_response=[CLIENT_1, UNBLOCKED], clients_response=[CLIENT_1, UNBLOCKED],
devices_response=[DEVICE_1], devices_response=[DEVICE_1],
) )
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2
poe_switch = hass.states.get("switch.poe_client_1") poe_switch = hass.states.get("switch.poe_client_1")
@ -438,11 +444,12 @@ async def test_remove_switches(hass, aioclient_mock):
block_switch = hass.states.get("switch.block_client_2") block_switch = hass.states.get("switch.block_client_2")
assert block_switch is not None assert block_switch is not None
controller.api.websocket._data = { mock_unifi_websocket(
"meta": {"message": MESSAGE_CLIENT_REMOVED}, data={
"data": [CLIENT_1, UNBLOCKED], "meta": {"message": MESSAGE_CLIENT_REMOVED},
} "data": [CLIENT_1, UNBLOCKED],
controller.api.session_handler(SIGNAL_DATA) }
)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0
@ -454,7 +461,7 @@ async def test_remove_switches(hass, aioclient_mock):
assert block_switch is None assert block_switch is None
async def test_block_switches(hass, aioclient_mock): async def test_block_switches(hass, aioclient_mock, mock_unifi_websocket):
"""Test the update_items function with some clients.""" """Test the update_items function with some clients."""
config_entry = await setup_unifi_integration( config_entry = await setup_unifi_integration(
hass, hass,
@ -479,11 +486,12 @@ async def test_block_switches(hass, aioclient_mock):
assert unblocked is not None assert unblocked is not None
assert unblocked.state == "on" assert unblocked.state == "on"
controller.api.websocket._data = { mock_unifi_websocket(
"meta": {"message": MESSAGE_EVENT}, data={
"data": [EVENT_BLOCKED_CLIENT_UNBLOCKED], "meta": {"message": MESSAGE_EVENT},
} "data": [EVENT_BLOCKED_CLIENT_UNBLOCKED],
controller.api.session_handler(SIGNAL_DATA) }
)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2
@ -491,11 +499,12 @@ async def test_block_switches(hass, aioclient_mock):
assert blocked is not None assert blocked is not None
assert blocked.state == "on" assert blocked.state == "on"
controller.api.websocket._data = { mock_unifi_websocket(
"meta": {"message": MESSAGE_EVENT}, data={
"data": [EVENT_BLOCKED_CLIENT_BLOCKED], "meta": {"message": MESSAGE_EVENT},
} "data": [EVENT_BLOCKED_CLIENT_BLOCKED],
controller.api.session_handler(SIGNAL_DATA) }
)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2
@ -526,9 +535,11 @@ async def test_block_switches(hass, aioclient_mock):
} }
async def test_new_client_discovered_on_block_control(hass, aioclient_mock): async def test_new_client_discovered_on_block_control(
hass, aioclient_mock, mock_unifi_websocket
):
"""Test if 2nd update has a new client.""" """Test if 2nd update has a new client."""
config_entry = await setup_unifi_integration( await setup_unifi_integration(
hass, hass,
aioclient_mock, aioclient_mock,
options={ options={
@ -538,27 +549,28 @@ async def test_new_client_discovered_on_block_control(hass, aioclient_mock):
CONF_DPI_RESTRICTIONS: False, CONF_DPI_RESTRICTIONS: False,
}, },
) )
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0
blocked = hass.states.get("switch.block_client_1") blocked = hass.states.get("switch.block_client_1")
assert blocked is None assert blocked is None
controller.api.websocket._data = { mock_unifi_websocket(
"meta": {"message": "sta:sync"}, data={
"data": [BLOCKED], "meta": {"message": "sta:sync"},
} "data": [BLOCKED],
controller.api.session_handler(SIGNAL_DATA) }
)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0
controller.api.websocket._data = { mock_unifi_websocket(
"meta": {"message": MESSAGE_EVENT}, data={
"data": [EVENT_BLOCKED_CLIENT_CONNECTED], "meta": {"message": MESSAGE_EVENT},
} "data": [EVENT_BLOCKED_CLIENT_CONNECTED],
controller.api.session_handler(SIGNAL_DATA) }
)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1
@ -634,7 +646,9 @@ async def test_option_remove_switches(hass, aioclient_mock):
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0
async def test_new_client_discovered_on_poe_control(hass, aioclient_mock): async def test_new_client_discovered_on_poe_control(
hass, aioclient_mock, mock_unifi_websocket
):
"""Test if 2nd update has a new client.""" """Test if 2nd update has a new client."""
config_entry = await setup_unifi_integration( config_entry = await setup_unifi_integration(
hass, hass,
@ -647,20 +661,22 @@ async def test_new_client_discovered_on_poe_control(hass, aioclient_mock):
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1
controller.api.websocket._data = { mock_unifi_websocket(
"meta": {"message": "sta:sync"}, data={
"data": [CLIENT_2], "meta": {"message": "sta:sync"},
} "data": [CLIENT_2],
controller.api.session_handler(SIGNAL_DATA) }
)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1
controller.api.websocket._data = { mock_unifi_websocket(
"meta": {"message": MESSAGE_EVENT}, data={
"data": [EVENT_CLIENT_2_CONNECTED], "meta": {"message": MESSAGE_EVENT},
} "data": [EVENT_CLIENT_2_CONNECTED],
controller.api.session_handler(SIGNAL_DATA) }
)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2 assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2