diff --git a/.coveragerc b/.coveragerc index 10530e1252f..27404dffc7f 100644 --- a/.coveragerc +++ b/.coveragerc @@ -917,9 +917,7 @@ omit = homeassistant/components/notion/util.py homeassistant/components/nsw_fuel_station/sensor.py homeassistant/components/nuki/__init__.py - homeassistant/components/nuki/binary_sensor.py homeassistant/components/nuki/lock.py - homeassistant/components/nuki/sensor.py homeassistant/components/nx584/alarm_control_panel.py homeassistant/components/oasa_telematics/sensor.py homeassistant/components/obihai/__init__.py diff --git a/tests/components/nuki/__init__.py b/tests/components/nuki/__init__.py index a774935b9db..d100e4b628e 100644 --- a/tests/components/nuki/__init__.py +++ b/tests/components/nuki/__init__.py @@ -1 +1,37 @@ """The tests for nuki integration.""" + +import requests_mock + +from homeassistant.components.nuki.const import DOMAIN +from homeassistant.core import HomeAssistant + +from .mock import MOCK_INFO, setup_nuki_integration + +from tests.common import ( + MockConfigEntry, + load_json_array_fixture, + load_json_object_fixture, +) + + +async def init_integration(hass: HomeAssistant) -> MockConfigEntry: + """Mock integration setup.""" + with requests_mock.Mocker() as mock: + # Mocking authentication endpoint + mock.get("http://1.1.1.1:8080/info", json=MOCK_INFO) + mock.get( + "http://1.1.1.1:8080/list", + json=load_json_array_fixture("list.json", DOMAIN), + ) + mock.get( + "http://1.1.1.1:8080/callback/list", + json=load_json_object_fixture("callback_list.json", DOMAIN), + ) + mock.get( + "http://1.1.1.1:8080/callback/add", + json=load_json_object_fixture("callback_add.json", DOMAIN), + ) + entry = await setup_nuki_integration(hass) + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + return entry diff --git a/tests/components/nuki/fixtures/callback_add.json b/tests/components/nuki/fixtures/callback_add.json new file mode 100644 index 00000000000..5550c6db40a --- /dev/null +++ b/tests/components/nuki/fixtures/callback_add.json @@ -0,0 +1,3 @@ +{ + "success": true +} diff --git a/tests/components/nuki/fixtures/callback_list.json b/tests/components/nuki/fixtures/callback_list.json new file mode 100644 index 00000000000..87da7f43884 --- /dev/null +++ b/tests/components/nuki/fixtures/callback_list.json @@ -0,0 +1,12 @@ +{ + "callbacks": [ + { + "id": 0, + "url": "http://192.168.0.20:8000/nuki" + }, + { + "id": 1, + "url": "http://192.168.0.21/test" + } + ] +} diff --git a/tests/components/nuki/fixtures/info.json b/tests/components/nuki/fixtures/info.json new file mode 100644 index 00000000000..2a81bdf6e52 --- /dev/null +++ b/tests/components/nuki/fixtures/info.json @@ -0,0 +1,27 @@ +{ + "bridgeType": 1, + "ids": { "hardwareId": 12345678, "serverId": 12345678 }, + "versions": { + "firmwareVersion": "0.1.0", + "wifiFirmwareVersion": "0.2.0" + }, + "uptime": 120, + "currentTime": "2018-04-01T12:10:11Z", + "serverConnected": true, + "scanResults": [ + { + "nukiId": 10, + "type": 0, + "name": "Nuki_00000010", + "rssi": -87, + "paired": true + }, + { + "nukiId": 2, + "deviceType": 11, + "name": "Nuki_00000011", + "rssi": -93, + "paired": false + } + ] +} diff --git a/tests/components/nuki/fixtures/list.json b/tests/components/nuki/fixtures/list.json new file mode 100644 index 00000000000..f92a32f3215 --- /dev/null +++ b/tests/components/nuki/fixtures/list.json @@ -0,0 +1,30 @@ +[ + { + "nukiId": 1, + "deviceType": 0, + "name": "Home", + "lastKnownState": { + "mode": 2, + "state": 1, + "stateName": "unlocked", + "batteryCritical": false, + "batteryCharging": false, + "batteryChargeState": 85, + "doorsensorState": 2, + "doorsensorStateName": "door closed", + "timestamp": "2018-10-03T06:49:00+00:00" + } + }, + { + "nukiId": 2, + "deviceType": 2, + "name": "Community door", + "lastKnownState": { + "mode": 3, + "state": 3, + "stateName": "rto active", + "batteryCritical": false, + "timestamp": "2018-10-03T06:49:00+00:00" + } + } +] diff --git a/tests/components/nuki/mock.py b/tests/components/nuki/mock.py index 56297240331..a6bb643b932 100644 --- a/tests/components/nuki/mock.py +++ b/tests/components/nuki/mock.py @@ -1,25 +1,29 @@ """Mockup Nuki device.""" -from tests.common import MockConfigEntry +from homeassistant.components.nuki.const import DOMAIN +from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TOKEN +from homeassistant.core import HomeAssistant -NAME = "Nuki_Bridge_75BCD15" +from tests.common import MockConfigEntry, load_json_object_fixture + +NAME = "Nuki_Bridge_BC614E" HOST = "1.1.1.1" MAC = "01:23:45:67:89:ab" DHCP_FORMATTED_MAC = "0123456789ab" -HW_ID = 123456789 -ID_HEX = "75BCD15" +HW_ID = 12345678 +ID_HEX = "BC614E" -MOCK_INFO = {"ids": {"hardwareId": HW_ID}} +MOCK_INFO = load_json_object_fixture("info.json", DOMAIN) -async def setup_nuki_integration(hass): +async def setup_nuki_integration(hass: HomeAssistant) -> MockConfigEntry: """Create the Nuki device.""" entry = MockConfigEntry( - domain="nuki", + domain=DOMAIN, unique_id=ID_HEX, - data={"host": HOST, "port": 8080, "token": "test-token"}, + data={CONF_HOST: HOST, CONF_PORT: 8080, CONF_TOKEN: "test-token"}, ) entry.add_to_hass(hass) diff --git a/tests/components/nuki/snapshots/test_binary_sensor.ambr b/tests/components/nuki/snapshots/test_binary_sensor.ambr new file mode 100644 index 00000000000..4a122fa78f2 --- /dev/null +++ b/tests/components/nuki/snapshots/test_binary_sensor.ambr @@ -0,0 +1,237 @@ +# serializer version: 1 +# name: test_binary_sensors[binary_sensor.community_door_battery-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.community_door_battery', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery', + 'platform': 'nuki', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '2_battery_critical', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[binary_sensor.community_door_battery-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'Community door Battery', + }), + 'context': , + 'entity_id': 'binary_sensor.community_door_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_binary_sensors[binary_sensor.community_door_ring_action-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.community_door_ring_action', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Ring Action', + 'platform': 'nuki', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'ring_action', + 'unique_id': '2_ringaction', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[binary_sensor.community_door_ring_action-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Community door Ring Action', + 'nuki_id': 2, + }), + 'context': , + 'entity_id': 'binary_sensor.community_door_ring_action', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_binary_sensors[binary_sensor.home-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.home', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': None, + 'platform': 'nuki', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '1_doorsensor', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[binary_sensor.home-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'door', + 'friendly_name': 'Home', + 'nuki_id': 1, + }), + 'context': , + 'entity_id': 'binary_sensor.home', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_binary_sensors[binary_sensor.home_battery-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.home_battery', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery', + 'platform': 'nuki', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '1_battery_critical', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[binary_sensor.home_battery-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'Home Battery', + }), + 'context': , + 'entity_id': 'binary_sensor.home_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_binary_sensors[binary_sensor.home_charging-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.home_charging', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Charging', + 'platform': 'nuki', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '1_battery_charging', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[binary_sensor.home_charging-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery_charging', + 'friendly_name': 'Home Charging', + }), + 'context': , + 'entity_id': 'binary_sensor.home_charging', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- diff --git a/tests/components/nuki/snapshots/test_lock.ambr b/tests/components/nuki/snapshots/test_lock.ambr new file mode 100644 index 00000000000..a0013fc37c1 --- /dev/null +++ b/tests/components/nuki/snapshots/test_lock.ambr @@ -0,0 +1,99 @@ +# serializer version: 1 +# name: test_locks[lock.community_door-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'lock', + 'entity_category': None, + 'entity_id': 'lock.community_door', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'nuki', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': 'nuki_lock', + 'unique_id': 2, + 'unit_of_measurement': None, + }) +# --- +# name: test_locks[lock.community_door-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'battery_critical': False, + 'friendly_name': 'Community door', + 'nuki_id': 2, + 'supported_features': , + }), + 'context': , + 'entity_id': 'lock.community_door', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unlocked', + }) +# --- +# name: test_locks[lock.home-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'lock', + 'entity_category': None, + 'entity_id': 'lock.home', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'nuki', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': 'nuki_lock', + 'unique_id': 1, + 'unit_of_measurement': None, + }) +# --- +# name: test_locks[lock.home-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'battery_critical': False, + 'friendly_name': 'Home', + 'nuki_id': 1, + 'supported_features': , + }), + 'context': , + 'entity_id': 'lock.home', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'locked', + }) +# --- diff --git a/tests/components/nuki/snapshots/test_sensor.ambr b/tests/components/nuki/snapshots/test_sensor.ambr new file mode 100644 index 00000000000..3c1159aecba --- /dev/null +++ b/tests/components/nuki/snapshots/test_sensor.ambr @@ -0,0 +1,50 @@ +# serializer version: 1 +# name: test_sensors[sensor.home_battery-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.home_battery', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery', + 'platform': 'nuki', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '1_battery_level', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensors[sensor.home_battery-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'Home Battery', + 'nuki_id': 1, + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.home_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '85', + }) +# --- diff --git a/tests/components/nuki/test_binary_sensor.py b/tests/components/nuki/test_binary_sensor.py new file mode 100644 index 00000000000..54fbc93c144 --- /dev/null +++ b/tests/components/nuki/test_binary_sensor.py @@ -0,0 +1,27 @@ +"""Tests for the nuki binary sensors.""" + +from unittest.mock import patch + +import pytest +from syrupy import SnapshotAssertion + +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from . import init_integration + +from tests.common import snapshot_platform + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default") +async def test_binary_sensors( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, +) -> None: + """Test binary sensors.""" + with patch("homeassistant.components.nuki.PLATFORMS", [Platform.BINARY_SENSOR]): + entry = await init_integration(hass) + + await snapshot_platform(hass, entity_registry, snapshot, entry.entry_id) diff --git a/tests/components/nuki/test_config_flow.py b/tests/components/nuki/test_config_flow.py index 58cbfde3d92..cdd429c40c5 100644 --- a/tests/components/nuki/test_config_flow.py +++ b/tests/components/nuki/test_config_flow.py @@ -8,7 +8,7 @@ from requests.exceptions import RequestException from homeassistant import config_entries from homeassistant.components import dhcp from homeassistant.components.nuki.const import DOMAIN -from homeassistant.const import CONF_TOKEN +from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TOKEN from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType @@ -37,19 +37,19 @@ async def test_form(hass: HomeAssistant) -> None: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { - "host": "1.1.1.1", - "port": 8080, - "token": "test-token", + CONF_HOST: "1.1.1.1", + CONF_PORT: 8080, + CONF_TOKEN: "test-token", }, ) await hass.async_block_till_done() assert result2["type"] is FlowResultType.CREATE_ENTRY - assert result2["title"] == "75BCD15" + assert result2["title"] == "BC614E" assert result2["data"] == { - "host": "1.1.1.1", - "port": 8080, - "token": "test-token", + CONF_HOST: "1.1.1.1", + CONF_PORT: 8080, + CONF_TOKEN: "test-token", } assert len(mock_setup_entry.mock_calls) == 1 @@ -67,9 +67,9 @@ async def test_form_invalid_auth(hass: HomeAssistant) -> None: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { - "host": "1.1.1.1", - "port": 8080, - "token": "test-token", + CONF_HOST: "1.1.1.1", + CONF_PORT: 8080, + CONF_TOKEN: "test-token", }, ) @@ -90,9 +90,9 @@ async def test_form_cannot_connect(hass: HomeAssistant) -> None: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { - "host": "1.1.1.1", - "port": 8080, - "token": "test-token", + CONF_HOST: "1.1.1.1", + CONF_PORT: 8080, + CONF_TOKEN: "test-token", }, ) @@ -113,9 +113,9 @@ async def test_form_unknown_exception(hass: HomeAssistant) -> None: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { - "host": "1.1.1.1", - "port": 8080, - "token": "test-token", + CONF_HOST: "1.1.1.1", + CONF_PORT: 8080, + CONF_TOKEN: "test-token", }, ) @@ -137,9 +137,9 @@ async def test_form_already_configured(hass: HomeAssistant) -> None: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { - "host": "1.1.1.1", - "port": 8080, - "token": "test-token", + CONF_HOST: "1.1.1.1", + CONF_PORT: 8080, + CONF_TOKEN: "test-token", }, ) @@ -173,18 +173,18 @@ async def test_dhcp_flow(hass: HomeAssistant) -> None: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { - "host": "1.1.1.1", - "port": 8080, - "token": "test-token", + CONF_HOST: "1.1.1.1", + CONF_PORT: 8080, + CONF_TOKEN: "test-token", }, ) assert result2["type"] is FlowResultType.CREATE_ENTRY - assert result2["title"] == "75BCD15" + assert result2["title"] == "BC614E" assert result2["data"] == { - "host": "1.1.1.1", - "port": 8080, - "token": "test-token", + CONF_HOST: "1.1.1.1", + CONF_PORT: 8080, + CONF_TOKEN: "test-token", } await hass.async_block_till_done() diff --git a/tests/components/nuki/test_lock.py b/tests/components/nuki/test_lock.py new file mode 100644 index 00000000000..824d508f3dc --- /dev/null +++ b/tests/components/nuki/test_lock.py @@ -0,0 +1,25 @@ +"""Tests for the nuki locks.""" + +from unittest.mock import patch + +from syrupy import SnapshotAssertion + +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from . import init_integration + +from tests.common import snapshot_platform + + +async def test_locks( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, +) -> None: + """Test locks.""" + with patch("homeassistant.components.nuki.PLATFORMS", [Platform.LOCK]): + entry = await init_integration(hass) + + await snapshot_platform(hass, entity_registry, snapshot, entry.entry_id) diff --git a/tests/components/nuki/test_sensor.py b/tests/components/nuki/test_sensor.py new file mode 100644 index 00000000000..dde803d573f --- /dev/null +++ b/tests/components/nuki/test_sensor.py @@ -0,0 +1,25 @@ +"""Tests for the nuki sensors.""" + +from unittest.mock import patch + +from syrupy import SnapshotAssertion + +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from . import init_integration + +from tests.common import snapshot_platform + + +async def test_sensors( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, +) -> None: + """Test sensors.""" + with patch("homeassistant.components.nuki.PLATFORMS", [Platform.SENSOR]): + entry = await init_integration(hass) + + await snapshot_platform(hass, entity_registry, snapshot, entry.entry_id)