From ee34dd8cfecd4c24f7b21de65929c5f3e436db6e Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Sun, 7 Aug 2022 22:07:55 +0100 Subject: [PATCH 01/10] add camera to prosegur --- homeassistant/components/prosegur/__init__.py | 2 +- .../prosegur/alarm_control_panel.py | 12 +++ homeassistant/components/prosegur/camera.py | 100 ++++++++++++++++++ homeassistant/components/prosegur/const.py | 2 + .../components/prosegur/diagnostics.py | 29 +++++ .../components/prosegur/manifest.json | 4 +- .../components/prosegur/services.yaml | 6 ++ requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 9 files changed, 154 insertions(+), 5 deletions(-) create mode 100644 homeassistant/components/prosegur/camera.py create mode 100644 homeassistant/components/prosegur/diagnostics.py create mode 100644 homeassistant/components/prosegur/services.yaml diff --git a/homeassistant/components/prosegur/__init__.py b/homeassistant/components/prosegur/__init__.py index 04f353e96b8a8..9f594fc6dae7c 100644 --- a/homeassistant/components/prosegur/__init__.py +++ b/homeassistant/components/prosegur/__init__.py @@ -11,7 +11,7 @@ from .const import CONF_COUNTRY, DOMAIN -PLATFORMS = [Platform.ALARM_CONTROL_PANEL] +PLATFORMS = [Platform.ALARM_CONTROL_PANEL, Platform.CAMERA] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/prosegur/alarm_control_panel.py b/homeassistant/components/prosegur/alarm_control_panel.py index 133c182e2cc55..b0364221b5439 100644 --- a/homeassistant/components/prosegur/alarm_control_panel.py +++ b/homeassistant/components/prosegur/alarm_control_panel.py @@ -15,6 +15,7 @@ STATE_ALARM_DISARMED, ) from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import DOMAIN @@ -59,6 +60,17 @@ def __init__(self, contract: str, auth: Auth) -> None: self._attr_name = f"contract {self.contract}" self._attr_unique_id = self.contract + @property + def device_info(self) -> DeviceInfo: + """Return device information about this entity.""" + return DeviceInfo( + name="Prosegur Alarm", + manufacturer="Prosegur", + model="smart", + identifiers={(DOMAIN, self.contract)}, + configuration_url="https://smart.prosegur.com", + ) + async def async_update(self) -> None: """Update alarm status.""" diff --git a/homeassistant/components/prosegur/camera.py b/homeassistant/components/prosegur/camera.py new file mode 100644 index 0000000000000..7881fd66f5325 --- /dev/null +++ b/homeassistant/components/prosegur/camera.py @@ -0,0 +1,100 @@ +"""Support for Prosegur cameras.""" +from __future__ import annotations + +import logging + +from pyprosegur.auth import Auth +from pyprosegur.exceptions import ProsegurException +from pyprosegur.installation import Camera as InstallationCamera, Installation + +from homeassistant.components.camera import Camera +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity import DeviceInfo +from homeassistant.helpers.entity_platform import ( + AddEntitiesCallback, + async_get_current_platform, +) + +from . import DOMAIN +from .const import SERVICE_REQUEST_IMAGE + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback +) -> None: + """Set up the Prosegur camera platform.""" + + platform = async_get_current_platform() + platform.async_register_entity_service( + SERVICE_REQUEST_IMAGE, + {}, + "async_request_image", + ) + + _installation = await Installation.retrieve(hass.data[DOMAIN][entry.entry_id]) + + async_add_entities( + [ + ProsegurCamera(_installation, camera, hass.data[DOMAIN][entry.entry_id]) + for camera in _installation.cameras + ], + update_before_add=True, + ) + + +class ProsegurCamera(Camera): + """Representation of a Smart Prosegur Camera.""" + + def __init__( + self, installation: Installation, camera: InstallationCamera, auth: Auth + ) -> None: + """Initialize Prosegur Camera component.""" + Camera.__init__(self) + + self._installation = installation + self._camera = camera + self._auth = auth + self._attr_name = camera.description + self._attr_unique_id = f"{self._installation.contract} {camera.id}" + + @property + def device_info(self) -> DeviceInfo: + """Return device information about this entity.""" + return DeviceInfo( + name=self._camera.description, + manufacturer="Prosegur", + model="smart camera", + identifiers={(DOMAIN, self._installation.contract)}, + configuration_url="https://smart.prosegur.com", + ) + + async def async_camera_image( + self, width: int | None = None, height: int | None = None + ) -> bytes | None: + """Return bytes of camera image.""" + + try: + _LOGGER.debug("Get image for %s", self._camera.description) + return await self._installation.get_image(self._auth, self._camera.id) + + except ProsegurException as err: + _LOGGER.error("Image %s doesn't exist: %s", self._camera.description, err) + + return None + + async def async_request_image(self): + """Request new image from the camera.""" + + try: + _LOGGER.debug("Request image for %s", self._camera.description) + await self._installation.request_image(self._auth, self._camera.id) + + except ProsegurException as err: + _LOGGER.error( + "Could not request image from camera %s: %s", + self._camera.description, + err, + ) diff --git a/homeassistant/components/prosegur/const.py b/homeassistant/components/prosegur/const.py index b066b320a1744..3f5b86919708e 100644 --- a/homeassistant/components/prosegur/const.py +++ b/homeassistant/components/prosegur/const.py @@ -3,3 +3,5 @@ DOMAIN = "prosegur" CONF_COUNTRY = "country" + +SERVICE_REQUEST_IMAGE = "request_image" diff --git a/homeassistant/components/prosegur/diagnostics.py b/homeassistant/components/prosegur/diagnostics.py new file mode 100644 index 0000000000000..f474e7ccd885c --- /dev/null +++ b/homeassistant/components/prosegur/diagnostics.py @@ -0,0 +1,29 @@ +"""Diagnostics support for Prosegur.""" +from __future__ import annotations + +from typing import Any + +from pyprosegur.installation import Installation + +from homeassistant.components.diagnostics import async_redact_data +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant + +from .const import DOMAIN + +TO_REDACT = {"description", "latitude", "longitude", "contractId", "address"} + + +async def async_get_config_entry_diagnostics( + hass: HomeAssistant, entry: ConfigEntry +) -> dict[str, Any]: + """Return diagnostics for a config entry.""" + + installation = await Installation.retrieve(hass.data[DOMAIN][entry.entry_id]) + + activity = await installation.activity(hass.data[DOMAIN][entry.entry_id]) + + return { + "installation": async_redact_data(installation.data, TO_REDACT), + "activity": async_redact_data(activity, {}), + } diff --git a/homeassistant/components/prosegur/manifest.json b/homeassistant/components/prosegur/manifest.json index 1827939d097a5..8fb7ce7463b14 100644 --- a/homeassistant/components/prosegur/manifest.json +++ b/homeassistant/components/prosegur/manifest.json @@ -4,7 +4,7 @@ "codeowners": ["@dgomes"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/prosegur", + "requirements": ["pyprosegur==0.0.8"], "iot_class": "cloud_polling", - "loggers": ["pyprosegur"], - "requirements": ["pyprosegur==0.0.5"] + "loggers": ["pyprosegur"] } diff --git a/homeassistant/components/prosegur/services.yaml b/homeassistant/components/prosegur/services.yaml new file mode 100644 index 0000000000000..f24a327bf8a52 --- /dev/null +++ b/homeassistant/components/prosegur/services.yaml @@ -0,0 +1,6 @@ +request_image: + name: Request Camera image + description: Request a new image from a Prosegur Camera + target: + entity: + domain: camera diff --git a/requirements_all.txt b/requirements_all.txt index 032305ac4656f..41ccebaf96214 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1884,7 +1884,7 @@ pypoint==2.3.0 pyprof2calltree==1.4.5 # homeassistant.components.prosegur -pyprosegur==0.0.5 +pyprosegur==0.0.8 # homeassistant.components.prusalink pyprusalink==1.1.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 867d89c6b7ebd..84b08b7137d94 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1364,7 +1364,7 @@ pypoint==2.3.0 pyprof2calltree==1.4.5 # homeassistant.components.prosegur -pyprosegur==0.0.5 +pyprosegur==0.0.8 # homeassistant.components.prusalink pyprusalink==1.1.0 From 50e690a0a952fc436e84fefae954d70bbd60a463 Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Sun, 7 Aug 2022 23:54:46 +0100 Subject: [PATCH 02/10] add tests --- tests/components/prosegur/conftest.py | 12 +++++ tests/components/prosegur/test_camera.py | 54 +++++++++++++++++++ tests/components/prosegur/test_diagnostics.py | 30 +++++++++++ 3 files changed, 96 insertions(+) create mode 100644 tests/components/prosegur/conftest.py create mode 100644 tests/components/prosegur/test_camera.py create mode 100644 tests/components/prosegur/test_diagnostics.py diff --git a/tests/components/prosegur/conftest.py b/tests/components/prosegur/conftest.py new file mode 100644 index 0000000000000..7871ff465841e --- /dev/null +++ b/tests/components/prosegur/conftest.py @@ -0,0 +1,12 @@ +"""Define test fixtures for Prosegur.""" +from unittest.mock import patch + +import pytest + + +@pytest.fixture(name="mock_prosegur_auth") +def mock_prosegur_auth(): + """Setups authentication.""" + + with patch("pyprosegur.auth.Auth.login", return_value=True): + yield diff --git a/tests/components/prosegur/test_camera.py b/tests/components/prosegur/test_camera.py new file mode 100644 index 0000000000000..4e5581a1f2148 --- /dev/null +++ b/tests/components/prosegur/test_camera.py @@ -0,0 +1,54 @@ +"""The camera tests for the prosegur platform.""" +from unittest.mock import AsyncMock, patch + +from pyprosegur.installation import Camera + +from homeassistant.components import camera +from homeassistant.components.camera import Image +from homeassistant.components.prosegur.const import DOMAIN +from homeassistant.const import ATTR_ENTITY_ID + +from .common import setup_platform + + +async def test_camera(hass, mock_prosegur_auth): + """Test prosegur get_image.""" + + install = AsyncMock() + install.contract = "123" + install.installationId = "1234abcd" + install.cameras = [Camera("1", "test_cam")] + install.get_image = AsyncMock(return_value=b"ABC") + + with patch("pyprosegur.installation.Installation.retrieve", return_value=install): + + await setup_platform(hass) + + await hass.async_block_till_done() + + image = await camera.async_get_image(hass, "camera.test_cam") + + assert image == Image(content_type="image/jpeg", content=b"ABC") + + +async def test_request_image(hass, mock_prosegur_auth): + """Test the camera request image service.""" + + install = AsyncMock() + install.contract = "123" + install.installationId = "1234abcd" + install.cameras = [Camera("1", "test_cam")] + install.request_image = AsyncMock() + + with patch("pyprosegur.installation.Installation.retrieve", return_value=install): + + await setup_platform(hass) + + await hass.services.async_call( + DOMAIN, + "request_image", + {ATTR_ENTITY_ID: "camera.test_cam"}, + ) + await hass.async_block_till_done() + + assert install.request_image.called diff --git a/tests/components/prosegur/test_diagnostics.py b/tests/components/prosegur/test_diagnostics.py new file mode 100644 index 0000000000000..247242e8adc49 --- /dev/null +++ b/tests/components/prosegur/test_diagnostics.py @@ -0,0 +1,30 @@ +"""Test Prosegur diagnostics.""" + +from unittest.mock import AsyncMock, patch + +from .common import setup_platform + +from tests.components.diagnostics import get_diagnostics_for_config_entry + + +async def test_diagnostics(hass, hass_client, mock_prosegur_auth): + """Test generating diagnostics for a config entry.""" + + install = AsyncMock() + install.data = {"contract": "123"} + install.activity = AsyncMock(return_value={"event": "armed"}) + + with patch("pyprosegur.installation.Installation.retrieve", return_value=install): + + await setup_platform(hass) + + await hass.async_block_till_done() + + entry = hass.config_entries.async_entries("prosegur")[0] + + diag = await get_diagnostics_for_config_entry(hass, hass_client, entry) + + assert diag == { + "installation": {"contract": "123"}, + "activity": {"event": "armed"}, + } From 82f4e3eadc586ed7026afbce6dd03c841fa2b970 Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Mon, 8 Aug 2022 18:38:44 +0100 Subject: [PATCH 03/10] address review --- homeassistant/components/prosegur/alarm_control_panel.py | 5 +---- homeassistant/components/prosegur/camera.py | 5 +---- homeassistant/components/prosegur/diagnostics.py | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/prosegur/alarm_control_panel.py b/homeassistant/components/prosegur/alarm_control_panel.py index b0364221b5439..cfcb07773f5c5 100644 --- a/homeassistant/components/prosegur/alarm_control_panel.py +++ b/homeassistant/components/prosegur/alarm_control_panel.py @@ -60,10 +60,7 @@ def __init__(self, contract: str, auth: Auth) -> None: self._attr_name = f"contract {self.contract}" self._attr_unique_id = self.contract - @property - def device_info(self) -> DeviceInfo: - """Return device information about this entity.""" - return DeviceInfo( + self._attr_device_info = DeviceInfo( name="Prosegur Alarm", manufacturer="Prosegur", model="smart", diff --git a/homeassistant/components/prosegur/camera.py b/homeassistant/components/prosegur/camera.py index 7881fd66f5325..40f8e18fb66c6 100644 --- a/homeassistant/components/prosegur/camera.py +++ b/homeassistant/components/prosegur/camera.py @@ -60,10 +60,7 @@ def __init__( self._attr_name = camera.description self._attr_unique_id = f"{self._installation.contract} {camera.id}" - @property - def device_info(self) -> DeviceInfo: - """Return device information about this entity.""" - return DeviceInfo( + self._attr_device_info = DeviceInfo( name=self._camera.description, manufacturer="Prosegur", model="smart camera", diff --git a/homeassistant/components/prosegur/diagnostics.py b/homeassistant/components/prosegur/diagnostics.py index f474e7ccd885c..d24456983488d 100644 --- a/homeassistant/components/prosegur/diagnostics.py +++ b/homeassistant/components/prosegur/diagnostics.py @@ -25,5 +25,5 @@ async def async_get_config_entry_diagnostics( return { "installation": async_redact_data(installation.data, TO_REDACT), - "activity": async_redact_data(activity, {}), + "activity": activity, } From 75a2d69c1f1463e48caf71cfc02c34260279ab64 Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Fri, 19 Aug 2022 00:20:06 +0100 Subject: [PATCH 04/10] better tests --- tests/components/prosegur/common.py | 27 -------- tests/components/prosegur/conftest.py | 59 +++++++++++++++-- .../prosegur/test_alarm_control_panel.py | 9 +-- tests/components/prosegur/test_camera.py | 63 ++++++++++++------- tests/components/prosegur/test_diagnostics.py | 24 +++---- tests/components/prosegur/test_init.py | 15 +---- 6 files changed, 106 insertions(+), 91 deletions(-) delete mode 100644 tests/components/prosegur/common.py diff --git a/tests/components/prosegur/common.py b/tests/components/prosegur/common.py deleted file mode 100644 index bed9d987cebf4..0000000000000 --- a/tests/components/prosegur/common.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Common methods used across tests for Prosegur.""" -from homeassistant.components.prosegur import DOMAIN as PROSEGUR_DOMAIN -from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -from homeassistant.setup import async_setup_component - -from tests.common import MockConfigEntry - -CONTRACT = "1234abcd" - - -async def setup_platform(hass): - """Set up the Prosegur platform.""" - mock_entry = MockConfigEntry( - domain=PROSEGUR_DOMAIN, - data={ - "contract": "1234abcd", - CONF_USERNAME: "user@email.com", - CONF_PASSWORD: "password", - "country": "PT", - }, - ) - mock_entry.add_to_hass(hass) - - assert await async_setup_component(hass, PROSEGUR_DOMAIN, {}) - await hass.async_block_till_done() - - return mock_entry diff --git a/tests/components/prosegur/conftest.py b/tests/components/prosegur/conftest.py index 7871ff465841e..3df05fec888e7 100644 --- a/tests/components/prosegur/conftest.py +++ b/tests/components/prosegur/conftest.py @@ -1,12 +1,59 @@ """Define test fixtures for Prosegur.""" -from unittest.mock import patch +from unittest.mock import AsyncMock, patch +from pyprosegur.installation import Camera import pytest +from homeassistant.components.prosegur import DOMAIN as PROSEGUR_DOMAIN +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME +from homeassistant.core import HomeAssistant -@pytest.fixture(name="mock_prosegur_auth") -def mock_prosegur_auth(): - """Setups authentication.""" +from tests.common import MockConfigEntry - with patch("pyprosegur.auth.Auth.login", return_value=True): - yield + +@pytest.fixture +def mock_config_entry() -> MockConfigEntry: + """Return the default mocked config entry.""" + return MockConfigEntry( + domain=PROSEGUR_DOMAIN, + data={ + "contract": "1234abcd", + CONF_USERNAME: "user@email.com", + CONF_PASSWORD: "password", + "country": "PT", + }, + ) + + +@pytest.fixture +def mock_install() -> AsyncMock: + """Return the mocked alarm install.""" + install = AsyncMock() + install.contract = "123" + install.installationId = "1234abcd" + install.cameras = [Camera("1", "test_cam")] + install.get_image = AsyncMock(return_value=b"ABC") + install.request_image = AsyncMock() + + install.data = {"contract": "123"} + install.activity = AsyncMock(return_value={"event": "armed"}) + + return install + + +@pytest.fixture +async def init_integration( + hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_install: AsyncMock +) -> MockConfigEntry: + """Set up the Prosegur integration for testing.""" + mock_config_entry.add_to_hass(hass) + + with patch( + "pyprosegur.installation.Installation.retrieve", return_value=mock_install + ): + + with patch("pyprosegur.auth.Auth.login", return_value=AsyncMock()): + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + return mock_config_entry diff --git a/tests/components/prosegur/test_alarm_control_panel.py b/tests/components/prosegur/test_alarm_control_panel.py index dce5e8d3c4e9b..db29c53395fc1 100644 --- a/tests/components/prosegur/test_alarm_control_panel.py +++ b/tests/components/prosegur/test_alarm_control_panel.py @@ -20,9 +20,8 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_component, entity_registry as er -from .common import CONTRACT, setup_platform - -PROSEGUR_ALARM_ENTITY = f"alarm_control_panel.contract_{CONTRACT}" +INSTALL_ID = "1234abcd" +PROSEGUR_ALARM_ENTITY = f"alarm_control_panel.contract_{INSTALL_ID}" @pytest.fixture @@ -48,12 +47,11 @@ def mock_status(request): async def test_entity_registry(hass: HomeAssistant, mock_auth, mock_status) -> None: """Tests that the devices are registered in the entity registry.""" - await setup_platform(hass) entity_registry = er.async_get(hass) entry = entity_registry.async_get(PROSEGUR_ALARM_ENTITY) # Prosegur alarm device unique_id is the contract id associated to the alarm account - assert entry.unique_id == CONTRACT + assert entry.unique_id == INSTALL_ID await hass.async_block_till_done() @@ -106,7 +104,6 @@ async def test_arm( install.status = code with patch("pyprosegur.installation.Installation.retrieve", return_value=install): - await setup_platform(hass) await hass.services.async_call( ALARM_DOMAIN, diff --git a/tests/components/prosegur/test_camera.py b/tests/components/prosegur/test_camera.py index 4e5581a1f2148..f81ad2f206e99 100644 --- a/tests/components/prosegur/test_camera.py +++ b/tests/components/prosegur/test_camera.py @@ -1,48 +1,61 @@ """The camera tests for the prosegur platform.""" -from unittest.mock import AsyncMock, patch +import logging +from unittest.mock import AsyncMock -from pyprosegur.installation import Camera +from pyprosegur.exceptions import ProsegurException from homeassistant.components import camera from homeassistant.components.camera import Image from homeassistant.components.prosegur.const import DOMAIN from homeassistant.const import ATTR_ENTITY_ID +from homeassistant.exceptions import HomeAssistantError -from .common import setup_platform - -async def test_camera(hass, mock_prosegur_auth): +async def test_camera(hass, init_integration): """Test prosegur get_image.""" - install = AsyncMock() - install.contract = "123" - install.installationId = "1234abcd" - install.cameras = [Camera("1", "test_cam")] - install.get_image = AsyncMock(return_value=b"ABC") + image = await camera.async_get_image(hass, "camera.test_cam") - with patch("pyprosegur.installation.Installation.retrieve", return_value=install): + assert image == Image(content_type="image/jpeg", content=b"ABC") - await setup_platform(hass) - await hass.async_block_till_done() +async def test_camera_fail(hass, init_integration, mock_install, caplog): + """Test prosegur get_image fails.""" - image = await camera.async_get_image(hass, "camera.test_cam") + mock_install.get_image = AsyncMock( + return_value=b"ABC", side_effect=ProsegurException() + ) - assert image == Image(content_type="image/jpeg", content=b"ABC") + with caplog.at_level(logging.ERROR, logger="homeassistant.components.prosegur"): + try: + await camera.async_get_image(hass, "camera.test_cam") + except HomeAssistantError as exc: + assert str(exc) == "Unable to get image" + else: + assert False + assert "Image test_cam doesn't exist" in caplog.text -async def test_request_image(hass, mock_prosegur_auth): + +async def test_request_image(hass, init_integration, mock_install): """Test the camera request image service.""" - install = AsyncMock() - install.contract = "123" - install.installationId = "1234abcd" - install.cameras = [Camera("1", "test_cam")] - install.request_image = AsyncMock() + await hass.services.async_call( + DOMAIN, + "request_image", + {ATTR_ENTITY_ID: "camera.test_cam"}, + ) + await hass.async_block_till_done() + + assert mock_install.request_image.called - with patch("pyprosegur.installation.Installation.retrieve", return_value=install): - await setup_platform(hass) +async def test_request_image_fail(hass, init_integration, mock_install, caplog): + """Test the camera request image service fails.""" + + mock_install.request_image = AsyncMock(side_effect=ProsegurException()) + + with caplog.at_level(logging.ERROR, logger="homeassistant.components.prosegur"): await hass.services.async_call( DOMAIN, @@ -51,4 +64,6 @@ async def test_request_image(hass, mock_prosegur_auth): ) await hass.async_block_till_done() - assert install.request_image.called + assert mock_install.request_image.called + + assert "Could not request image from camera test_cam" in caplog.text diff --git a/tests/components/prosegur/test_diagnostics.py b/tests/components/prosegur/test_diagnostics.py index 247242e8adc49..7a1baf4bc03bf 100644 --- a/tests/components/prosegur/test_diagnostics.py +++ b/tests/components/prosegur/test_diagnostics.py @@ -1,28 +1,20 @@ """Test Prosegur diagnostics.""" -from unittest.mock import AsyncMock, patch - -from .common import setup_platform +from unittest.mock import patch from tests.components.diagnostics import get_diagnostics_for_config_entry -async def test_diagnostics(hass, hass_client, mock_prosegur_auth): +async def test_diagnostics(hass, hass_client, init_integration, mock_install): """Test generating diagnostics for a config entry.""" - install = AsyncMock() - install.data = {"contract": "123"} - install.activity = AsyncMock(return_value={"event": "armed"}) - - with patch("pyprosegur.installation.Installation.retrieve", return_value=install): - - await setup_platform(hass) - - await hass.async_block_till_done() - - entry = hass.config_entries.async_entries("prosegur")[0] + with patch( + "pyprosegur.installation.Installation.retrieve", return_value=mock_install + ): - diag = await get_diagnostics_for_config_entry(hass, hass_client, entry) + diag = await get_diagnostics_for_config_entry( + hass, hass_client, init_integration + ) assert diag == { "installation": {"contract": "123"}, diff --git a/tests/components/prosegur/test_init.py b/tests/components/prosegur/test_init.py index 7f0373ea93d76..f25c97afed420 100644 --- a/tests/components/prosegur/test_init.py +++ b/tests/components/prosegur/test_init.py @@ -1,5 +1,5 @@ """Tests prosegur setup.""" -from unittest.mock import MagicMock, patch +from unittest.mock import patch import pytest @@ -20,22 +20,13 @@ async def test_setup_entry_fail_retrieve(hass: HomeAssistant, error) -> None: """Test loading the Prosegur entry.""" - config_entry = MockConfigEntry( - domain=DOMAIN, - data={ - "username": "test-username", - "password": "test-password", - "country": "PT", - "contract": "xpto", - }, - ) - config_entry.add_to_hass(hass) + mock_config_entry.add_to_hass(hass) with patch( "pyprosegur.auth.Auth.login", side_effect=error, ): - assert not await hass.config_entries.async_setup(config_entry.entry_id) + assert not await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() From 817f0363d41c69308460c6838d17a1fe0c8d45e3 Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Fri, 19 Aug 2022 00:51:27 +0100 Subject: [PATCH 05/10] clean --- tests/components/prosegur/conftest.py | 9 +++++---- .../components/prosegur/test_alarm_control_panel.py | 12 ++++++------ tests/components/prosegur/test_diagnostics.py | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/tests/components/prosegur/conftest.py b/tests/components/prosegur/conftest.py index 3df05fec888e7..69be349ebdd41 100644 --- a/tests/components/prosegur/conftest.py +++ b/tests/components/prosegur/conftest.py @@ -10,6 +10,8 @@ from tests.common import MockConfigEntry +CONTRACT = "1234abcd" + @pytest.fixture def mock_config_entry() -> MockConfigEntry: @@ -17,7 +19,7 @@ def mock_config_entry() -> MockConfigEntry: return MockConfigEntry( domain=PROSEGUR_DOMAIN, data={ - "contract": "1234abcd", + "contract": CONTRACT, CONF_USERNAME: "user@email.com", CONF_PASSWORD: "password", "country": "PT", @@ -29,13 +31,12 @@ def mock_config_entry() -> MockConfigEntry: def mock_install() -> AsyncMock: """Return the mocked alarm install.""" install = AsyncMock() - install.contract = "123" - install.installationId = "1234abcd" + install.contract = CONTRACT install.cameras = [Camera("1", "test_cam")] install.get_image = AsyncMock(return_value=b"ABC") install.request_image = AsyncMock() - install.data = {"contract": "123"} + install.data = {"contract": CONTRACT} install.activity = AsyncMock(return_value={"event": "armed"}) return install diff --git a/tests/components/prosegur/test_alarm_control_panel.py b/tests/components/prosegur/test_alarm_control_panel.py index db29c53395fc1..587ebd66a39d0 100644 --- a/tests/components/prosegur/test_alarm_control_panel.py +++ b/tests/components/prosegur/test_alarm_control_panel.py @@ -20,8 +20,9 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_component, entity_registry as er -INSTALL_ID = "1234abcd" -PROSEGUR_ALARM_ENTITY = f"alarm_control_panel.contract_{INSTALL_ID}" +from .conftest import CONTRACT + +PROSEGUR_ALARM_ENTITY = f"alarm_control_panel.contract_{CONTRACT}" @pytest.fixture @@ -37,8 +38,7 @@ def mock_status(request): """Mock the status of the alarm.""" install = AsyncMock() - install.contract = "123" - install.installationId = "1234abcd" + install.contract = CONTRACT install.status = request.param with patch("pyprosegur.installation.Installation.retrieve", return_value=install): @@ -51,13 +51,13 @@ async def test_entity_registry(hass: HomeAssistant, mock_auth, mock_status) -> N entry = entity_registry.async_get(PROSEGUR_ALARM_ENTITY) # Prosegur alarm device unique_id is the contract id associated to the alarm account - assert entry.unique_id == INSTALL_ID + assert entry.unique_id == CONTRACT await hass.async_block_till_done() state = hass.states.get(PROSEGUR_ALARM_ENTITY) - assert state.attributes.get(ATTR_FRIENDLY_NAME) == "contract 1234abcd" + assert state.attributes.get(ATTR_FRIENDLY_NAME) == f"contract {CONTRACT}" assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 3 diff --git a/tests/components/prosegur/test_diagnostics.py b/tests/components/prosegur/test_diagnostics.py index 7a1baf4bc03bf..ecb50230d8643 100644 --- a/tests/components/prosegur/test_diagnostics.py +++ b/tests/components/prosegur/test_diagnostics.py @@ -17,6 +17,6 @@ async def test_diagnostics(hass, hass_client, init_integration, mock_install): ) assert diag == { - "installation": {"contract": "123"}, + "installation": {"contract": "1234abcd"}, "activity": {"event": "armed"}, } From 93fbaa77d2ea943296d5b4b00ff1f1ae85b17586 Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Fri, 19 Aug 2022 00:55:24 +0100 Subject: [PATCH 06/10] clean --- tests/components/prosegur/conftest.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/components/prosegur/conftest.py b/tests/components/prosegur/conftest.py index 69be349ebdd41..ea906fdcbff45 100644 --- a/tests/components/prosegur/conftest.py +++ b/tests/components/prosegur/conftest.py @@ -51,10 +51,8 @@ async def init_integration( with patch( "pyprosegur.installation.Installation.retrieve", return_value=mock_install - ): + ), patch("pyprosegur.auth.Auth.login", return_value=AsyncMock()): + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() - with patch("pyprosegur.auth.Auth.login", return_value=AsyncMock()): - await hass.config_entries.async_setup(mock_config_entry.entry_id) - await hass.async_block_till_done() - - return mock_config_entry + return mock_config_entry From 16055c3e8f8e41120085867da96df99248c0fcae Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Fri, 24 Feb 2023 16:10:35 +0000 Subject: [PATCH 07/10] fix tests --- .../prosegur/test_alarm_control_panel.py | 13 +++--- tests/components/prosegur/test_init.py | 40 ++++--------------- 2 files changed, 15 insertions(+), 38 deletions(-) diff --git a/tests/components/prosegur/test_alarm_control_panel.py b/tests/components/prosegur/test_alarm_control_panel.py index 587ebd66a39d0..51086e74b00e0 100644 --- a/tests/components/prosegur/test_alarm_control_panel.py +++ b/tests/components/prosegur/test_alarm_control_panel.py @@ -45,7 +45,9 @@ def mock_status(request): yield -async def test_entity_registry(hass: HomeAssistant, mock_auth, mock_status) -> None: +async def test_entity_registry( + hass: HomeAssistant, init_integration, mock_auth, mock_status +) -> None: """Tests that the devices are registered in the entity registry.""" entity_registry = er.async_get(hass) @@ -61,7 +63,9 @@ async def test_entity_registry(hass: HomeAssistant, mock_auth, mock_status) -> N assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 3 -async def test_connection_error(hass: HomeAssistant, mock_auth) -> None: +async def test_connection_error( + hass: HomeAssistant, init_integration, mock_auth, mock_config_entry +) -> None: """Test the alarm control panel when connection can't be made to the cloud service.""" install = AsyncMock() @@ -71,8 +75,6 @@ async def test_connection_error(hass: HomeAssistant, mock_auth) -> None: install.status = Status.ARMED with patch("pyprosegur.installation.Installation.retrieve", return_value=install): - await setup_platform(hass) - await hass.async_block_till_done() with patch( @@ -93,7 +95,7 @@ async def test_connection_error(hass: HomeAssistant, mock_auth) -> None: ], ) async def test_arm( - hass: HomeAssistant, mock_auth, code, alarm_service, alarm_state + hass: HomeAssistant, init_integration, mock_auth, code, alarm_service, alarm_state ) -> None: """Test the alarm control panel can be set to away.""" @@ -104,7 +106,6 @@ async def test_arm( install.status = code with patch("pyprosegur.installation.Installation.retrieve", return_value=install): - await hass.services.async_call( ALARM_DOMAIN, alarm_service, diff --git a/tests/components/prosegur/test_init.py b/tests/components/prosegur/test_init.py index f25c97afed420..cdc7135cf1f54 100644 --- a/tests/components/prosegur/test_init.py +++ b/tests/components/prosegur/test_init.py @@ -3,10 +3,8 @@ import pytest -from homeassistant.components.prosegur import DOMAIN from homeassistant.core import HomeAssistant -from tests.common import MockConfigEntry from tests.test_util.aiohttp import AiohttpClientMocker @@ -17,7 +15,9 @@ ConnectionError, ], ) -async def test_setup_entry_fail_retrieve(hass: HomeAssistant, error) -> None: +async def test_setup_entry_fail_retrieve( + hass: HomeAssistant, mock_config_entry, error +) -> None: """Test loading the Prosegur entry.""" mock_config_entry.add_to_hass(hass) @@ -32,35 +32,11 @@ async def test_setup_entry_fail_retrieve(hass: HomeAssistant, error) -> None: async def test_unload_entry( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + init_integration, + mock_config_entry, + aioclient_mock: AiohttpClientMocker, ) -> None: """Test unloading the Prosegur entry.""" - aioclient_mock.post( - "https://smart.prosegur.com/smart-server/ws/access/login", - json={"data": {"token": "123456789"}}, - ) - - config_entry = MockConfigEntry( - domain=DOMAIN, - data={ - "username": "test-username", - "password": "test-password", - "country": "PT", - "contract": "xpto", - }, - ) - config_entry.add_to_hass(hass) - - install = MagicMock() - install.contract = "123" - - with patch( - "homeassistant.components.prosegur.config_flow.Installation.retrieve", - return_value=install, - ): - assert await hass.config_entries.async_setup(config_entry.entry_id) - - await hass.async_block_till_done() - - assert await hass.config_entries.async_unload(config_entry.entry_id) + assert await hass.config_entries.async_unload(mock_config_entry.entry_id) From 4bdd855baac5678604d8cc9efbf03acd2aab70ea Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Fri, 24 Feb 2023 16:45:15 +0000 Subject: [PATCH 08/10] leftover from merge --- tests/components/prosegur/test_camera.py | 4 ++-- tests/components/prosegur/test_diagnostics.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/components/prosegur/test_camera.py b/tests/components/prosegur/test_camera.py index f81ad2f206e99..75e4cbbc77380 100644 --- a/tests/components/prosegur/test_camera.py +++ b/tests/components/prosegur/test_camera.py @@ -3,6 +3,7 @@ from unittest.mock import AsyncMock from pyprosegur.exceptions import ProsegurException +import pytest from homeassistant.components import camera from homeassistant.components.camera import Image @@ -32,7 +33,7 @@ async def test_camera_fail(hass, init_integration, mock_install, caplog): except HomeAssistantError as exc: assert str(exc) == "Unable to get image" else: - assert False + assert pytest.fail() assert "Image test_cam doesn't exist" in caplog.text @@ -56,7 +57,6 @@ async def test_request_image_fail(hass, init_integration, mock_install, caplog): mock_install.request_image = AsyncMock(side_effect=ProsegurException()) with caplog.at_level(logging.ERROR, logger="homeassistant.components.prosegur"): - await hass.services.async_call( DOMAIN, "request_image", diff --git a/tests/components/prosegur/test_diagnostics.py b/tests/components/prosegur/test_diagnostics.py index ecb50230d8643..85377833a74fe 100644 --- a/tests/components/prosegur/test_diagnostics.py +++ b/tests/components/prosegur/test_diagnostics.py @@ -11,7 +11,6 @@ async def test_diagnostics(hass, hass_client, init_integration, mock_install): with patch( "pyprosegur.installation.Installation.retrieve", return_value=mock_install ): - diag = await get_diagnostics_for_config_entry( hass, hass_client, init_integration ) From c535be04997531a2d3b418d3ac48d690e799fc30 Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Fri, 24 Feb 2023 16:58:02 +0000 Subject: [PATCH 09/10] sorting missing --- homeassistant/components/prosegur/manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/prosegur/manifest.json b/homeassistant/components/prosegur/manifest.json index 8fb7ce7463b14..d5081a82dbfc3 100644 --- a/homeassistant/components/prosegur/manifest.json +++ b/homeassistant/components/prosegur/manifest.json @@ -4,7 +4,7 @@ "codeowners": ["@dgomes"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/prosegur", - "requirements": ["pyprosegur==0.0.8"], "iot_class": "cloud_polling", - "loggers": ["pyprosegur"] + "loggers": ["pyprosegur"], + "requirements": ["pyprosegur==0.0.8"] } From 874a34c90a38e51c5837e438f4da8b5b2270cf0b Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Sun, 26 Feb 2023 14:43:32 +0000 Subject: [PATCH 10/10] Update homeassistant/components/prosegur/services.yaml Co-authored-by: Paulus Schoutsen --- homeassistant/components/prosegur/services.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/prosegur/services.yaml b/homeassistant/components/prosegur/services.yaml index f24a327bf8a52..0db63cb7adf88 100644 --- a/homeassistant/components/prosegur/services.yaml +++ b/homeassistant/components/prosegur/services.yaml @@ -4,3 +4,4 @@ request_image: target: entity: domain: camera + integration: prosegur