mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +00:00
Add some basic tests for doorbird (#122135)
* basic tests * basic tests * basic tests * basic tests * cover * cover * Update tests/components/doorbird/test_init.py
This commit is contained in:
parent
d2cc25cee6
commit
a0a5f640dc
@ -1 +1,40 @@
|
||||
"""Tests for the DoorBird integration."""
|
||||
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock, MagicMock, Mock
|
||||
|
||||
import aiohttp
|
||||
from doorbirdpy import DoorBird, DoorBirdScheduleEntry
|
||||
|
||||
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_USERNAME
|
||||
|
||||
VALID_CONFIG = {
|
||||
CONF_HOST: "1.2.3.4",
|
||||
CONF_USERNAME: "friend",
|
||||
CONF_PASSWORD: "password",
|
||||
CONF_NAME: "mydoorbird",
|
||||
}
|
||||
|
||||
|
||||
def mock_unauthorized_exception() -> aiohttp.ClientResponseError:
|
||||
"""Return a mock unauthorized exception."""
|
||||
return aiohttp.ClientResponseError(request_info=Mock(), history=Mock(), status=401)
|
||||
|
||||
|
||||
def get_mock_doorbird_api(
|
||||
info: dict[str, Any] | None = None,
|
||||
info_side_effect: Exception | None = None,
|
||||
schedule: list[DoorBirdScheduleEntry] | None = None,
|
||||
) -> DoorBird:
|
||||
"""Return a mock DoorBirdAPI object with return values."""
|
||||
doorbirdapi_mock = MagicMock(spec_set=DoorBird)
|
||||
type(doorbirdapi_mock).info = AsyncMock(
|
||||
side_effect=info_side_effect, return_value=info
|
||||
)
|
||||
type(doorbirdapi_mock).favorites = AsyncMock(return_value={})
|
||||
type(doorbirdapi_mock).change_favorite = AsyncMock(return_value=True)
|
||||
type(doorbirdapi_mock).schedule = AsyncMock(return_value=schedule)
|
||||
type(doorbirdapi_mock).doorbell_state = AsyncMock(
|
||||
side_effect=mock_unauthorized_exception()
|
||||
)
|
||||
return doorbirdapi_mock
|
||||
|
101
tests/components/doorbird/conftest.py
Normal file
101
tests/components/doorbird/conftest.py
Normal file
@ -0,0 +1,101 @@
|
||||
"""Test configuration for DoorBird tests."""
|
||||
|
||||
from collections.abc import Generator
|
||||
from contextlib import contextmanager
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from doorbirdpy import DoorBird, DoorBirdScheduleEntry
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.doorbird.const import CONF_EVENTS, DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import VALID_CONFIG, get_mock_doorbird_api
|
||||
|
||||
from tests.common import MockConfigEntry, load_json_value_fixture
|
||||
|
||||
|
||||
@dataclass
|
||||
class MockDoorbirdEntry:
|
||||
"""Mock DoorBird config entry."""
|
||||
|
||||
entry: MockConfigEntry
|
||||
api: MagicMock
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def doorbird_info() -> dict[str, Any]:
|
||||
"""Return a loaded DoorBird info fixture."""
|
||||
return load_json_value_fixture("info.json", "doorbird")["BHA"]["VERSION"][0]
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def doorbird_schedule() -> list[DoorBirdScheduleEntry]:
|
||||
"""Return a loaded DoorBird schedule fixture."""
|
||||
return DoorBirdScheduleEntry.parse_all(
|
||||
load_json_value_fixture("schedule.json", "doorbird")
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def doorbird_api(
|
||||
doorbird_info: dict[str, Any], doorbird_schedule: dict[str, Any]
|
||||
) -> Generator[Any, Any, DoorBird]:
|
||||
"""Mock the DoorBirdAPI."""
|
||||
api = get_mock_doorbird_api(info=doorbird_info, schedule=doorbird_schedule)
|
||||
with patch_doorbird_api_entry_points(api):
|
||||
yield api
|
||||
|
||||
|
||||
@contextmanager
|
||||
def patch_doorbird_api_entry_points(api: MagicMock) -> Generator[Any, Any, DoorBird]:
|
||||
"""Mock the DoorBirdAPI."""
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.doorbird.DoorBird",
|
||||
return_value=api,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.doorbird.config_flow.DoorBird",
|
||||
return_value=api,
|
||||
),
|
||||
):
|
||||
yield api
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def doorbird_mocker(
|
||||
hass: HomeAssistant,
|
||||
doorbird_info: dict[str, Any],
|
||||
doorbird_schedule: dict[str, Any],
|
||||
) -> MockDoorbirdEntry:
|
||||
"""Create a MockDoorbirdEntry."""
|
||||
|
||||
async def _async_mock(
|
||||
entry: MockConfigEntry | None = None,
|
||||
api: DoorBird | None = None,
|
||||
info: dict[str, Any] | None = None,
|
||||
info_side_effect: Exception | None = None,
|
||||
schedule: list[DoorBirdScheduleEntry] | None = None,
|
||||
) -> None:
|
||||
"""Create a MockDoorbirdEntry from defaults or specific values."""
|
||||
entry = entry or MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="1CCAE3AAAAAA",
|
||||
data=VALID_CONFIG,
|
||||
options={CONF_EVENTS: ["event1", "event2", "event3"]},
|
||||
)
|
||||
api = api or get_mock_doorbird_api(
|
||||
info=info or doorbird_info,
|
||||
info_side_effect=info_side_effect,
|
||||
schedule=schedule or doorbird_schedule,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
with patch_doorbird_api_entry_points(api):
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
return MockDoorbirdEntry(entry=entry, api=api)
|
||||
|
||||
return _async_mock
|
23
tests/components/doorbird/fixtures/info.json
Normal file
23
tests/components/doorbird/fixtures/info.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"BHA": {
|
||||
"RETURNCODE": "1",
|
||||
"VERSION": [
|
||||
{
|
||||
"FIRMWARE": "000125",
|
||||
"BUILD_NUMBER": "15870439",
|
||||
"WIFI_MAC_ADDR": "1234ABCD",
|
||||
"RELAYS": [
|
||||
"1",
|
||||
"2",
|
||||
"ghchdi@1",
|
||||
"ghchdi@2",
|
||||
"ghchdi@3",
|
||||
"ghdwkh@1",
|
||||
"ghdwkh@2",
|
||||
"ghdwkh@3"
|
||||
],
|
||||
"DEVICE-TYPE": "DoorBird D2101V"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
67
tests/components/doorbird/fixtures/schedule.json
Normal file
67
tests/components/doorbird/fixtures/schedule.json
Normal file
@ -0,0 +1,67 @@
|
||||
[
|
||||
{
|
||||
"input": "doorbell",
|
||||
"param": "1",
|
||||
"output": [
|
||||
{
|
||||
"event": "notify",
|
||||
"param": "",
|
||||
"schedule": {
|
||||
"weekdays": [
|
||||
{
|
||||
"to": "107999",
|
||||
"from": "108000"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"event": "http",
|
||||
"param": "0",
|
||||
"schedule": {
|
||||
"weekdays": [
|
||||
{
|
||||
"to": "107999",
|
||||
"from": "108000"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"input": "motion",
|
||||
"param": "",
|
||||
"output": [
|
||||
{
|
||||
"event": "notify",
|
||||
"param": "",
|
||||
"schedule": {
|
||||
"weekdays": [
|
||||
{
|
||||
"to": "107999",
|
||||
"from": "108000"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"event": "http",
|
||||
"param": "5",
|
||||
"schedule": {
|
||||
"weekdays": [
|
||||
{
|
||||
"to": "107999",
|
||||
"from": "108000"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"input": "relay",
|
||||
"param": "1",
|
||||
"output": []
|
||||
}
|
||||
]
|
@ -1,9 +1,10 @@
|
||||
"""Test the DoorBird config flow."""
|
||||
|
||||
from ipaddress import ip_address
|
||||
from unittest.mock import AsyncMock, MagicMock, Mock, patch
|
||||
from unittest.mock import AsyncMock, Mock, patch
|
||||
|
||||
import aiohttp
|
||||
from doorbirdpy import DoorBird
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries
|
||||
@ -18,35 +19,12 @@ from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_USERNA
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
|
||||
from . import VALID_CONFIG, get_mock_doorbird_api, mock_unauthorized_exception
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
VALID_CONFIG = {
|
||||
CONF_HOST: "1.2.3.4",
|
||||
CONF_USERNAME: "friend",
|
||||
CONF_PASSWORD: "password",
|
||||
CONF_NAME: "mydoorbird",
|
||||
}
|
||||
|
||||
|
||||
def _get_mock_doorbirdapi_return_values(info=None):
|
||||
doorbirdapi_mock = MagicMock()
|
||||
type(doorbirdapi_mock).info = AsyncMock(return_value=info)
|
||||
type(doorbirdapi_mock).doorbell_state = AsyncMock(
|
||||
side_effect=aiohttp.ClientResponseError(
|
||||
request_info=Mock(), history=Mock(), status=401
|
||||
)
|
||||
)
|
||||
return doorbirdapi_mock
|
||||
|
||||
|
||||
def _get_mock_doorbirdapi_side_effects(info=None):
|
||||
doorbirdapi_mock = MagicMock()
|
||||
type(doorbirdapi_mock).info = AsyncMock(side_effect=info)
|
||||
|
||||
return doorbirdapi_mock
|
||||
|
||||
|
||||
async def test_user_form(hass: HomeAssistant) -> None:
|
||||
async def test_user_form(hass: HomeAssistant, doorbird_api: DoorBird) -> None:
|
||||
"""Test we get the user form."""
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
@ -55,12 +33,7 @@ async def test_user_form(hass: HomeAssistant) -> None:
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["errors"] == {}
|
||||
|
||||
doorbirdapi = _get_mock_doorbirdapi_return_values(info={"WIFI_MAC_ADDR": "macaddr"})
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.doorbird.config_flow.DoorBird",
|
||||
return_value=doorbirdapi,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.doorbird.async_setup", return_value=True
|
||||
) as mock_setup,
|
||||
@ -178,37 +151,30 @@ async def test_form_zeroconf_non_ipv4_ignored(hass: HomeAssistant) -> None:
|
||||
assert result["reason"] == "not_ipv4_address"
|
||||
|
||||
|
||||
async def test_form_zeroconf_correct_oui(hass: HomeAssistant) -> None:
|
||||
async def test_form_zeroconf_correct_oui(
|
||||
hass: HomeAssistant, doorbird_api: DoorBird
|
||||
) -> None:
|
||||
"""Test we can setup from zeroconf with the correct OUI source."""
|
||||
doorbirdapi = _get_mock_doorbirdapi_return_values(info={"WIFI_MAC_ADDR": "macaddr"})
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.doorbird.config_flow.DoorBird",
|
||||
return_value=doorbirdapi,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||
data=zeroconf.ZeroconfServiceInfo(
|
||||
ip_address=ip_address("192.168.1.5"),
|
||||
ip_addresses=[ip_address("192.168.1.5")],
|
||||
hostname="mock_hostname",
|
||||
name="Doorstation - abc123._axis-video._tcp.local.",
|
||||
port=None,
|
||||
properties={"macaddress": "1CCAE3DOORBIRD"},
|
||||
type="mock_type",
|
||||
),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||
data=zeroconf.ZeroconfServiceInfo(
|
||||
ip_address=ip_address("192.168.1.5"),
|
||||
ip_addresses=[ip_address("192.168.1.5")],
|
||||
hostname="mock_hostname",
|
||||
name="Doorstation - abc123._axis-video._tcp.local.",
|
||||
port=None,
|
||||
properties={"macaddress": "1CCAE3DOORBIRD"},
|
||||
type="mock_type",
|
||||
),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {}
|
||||
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.doorbird.config_flow.DoorBird",
|
||||
return_value=doorbirdapi,
|
||||
),
|
||||
patch("homeassistant.components.logbook.async_setup", return_value=True),
|
||||
patch(
|
||||
"homeassistant.components.doorbird.async_setup", return_value=True
|
||||
@ -244,10 +210,12 @@ async def test_form_zeroconf_correct_oui(hass: HomeAssistant) -> None:
|
||||
],
|
||||
)
|
||||
async def test_form_zeroconf_correct_oui_wrong_device(
|
||||
hass: HomeAssistant, doorbell_state_side_effect
|
||||
hass: HomeAssistant,
|
||||
doorbird_api: DoorBird,
|
||||
doorbell_state_side_effect: Exception | None,
|
||||
) -> None:
|
||||
"""Test we can setup from zeroconf with the correct OUI source but not a doorstation."""
|
||||
doorbirdapi = _get_mock_doorbirdapi_return_values(info={"WIFI_MAC_ADDR": "macaddr"})
|
||||
doorbirdapi = get_mock_doorbird_api(info={"WIFI_MAC_ADDR": "macaddr"})
|
||||
type(doorbirdapi).doorbell_state = AsyncMock(side_effect=doorbell_state_side_effect)
|
||||
|
||||
with patch(
|
||||
@ -278,7 +246,7 @@ async def test_form_user_cannot_connect(hass: HomeAssistant) -> None:
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
doorbirdapi = _get_mock_doorbirdapi_side_effects(info=OSError)
|
||||
doorbirdapi = get_mock_doorbird_api(info_side_effect=OSError)
|
||||
with patch(
|
||||
"homeassistant.components.doorbird.config_flow.DoorBird",
|
||||
return_value=doorbirdapi,
|
||||
@ -298,10 +266,8 @@ async def test_form_user_invalid_auth(hass: HomeAssistant) -> None:
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
mock_error = aiohttp.ClientResponseError(
|
||||
request_info=Mock(), history=Mock(), status=401
|
||||
)
|
||||
doorbirdapi = _get_mock_doorbirdapi_side_effects(info=mock_error)
|
||||
mock_error = mock_unauthorized_exception()
|
||||
doorbirdapi = get_mock_doorbird_api(info_side_effect=mock_error)
|
||||
with patch(
|
||||
"homeassistant.components.doorbird.config_flow.DoorBird",
|
||||
return_value=doorbirdapi,
|
||||
@ -360,10 +326,8 @@ async def test_reauth(hass: HomeAssistant) -> None:
|
||||
assert len(flows) == 1
|
||||
flow = flows[0]
|
||||
|
||||
mock_error = aiohttp.ClientResponseError(
|
||||
request_info=Mock(), history=Mock(), status=401
|
||||
)
|
||||
doorbirdapi = _get_mock_doorbirdapi_side_effects(info=mock_error)
|
||||
mock_error = mock_unauthorized_exception()
|
||||
doorbirdapi = get_mock_doorbird_api(info_side_effect=mock_error)
|
||||
with patch(
|
||||
"homeassistant.components.doorbird.config_flow.DoorBird",
|
||||
return_value=doorbirdapi,
|
||||
@ -379,7 +343,7 @@ async def test_reauth(hass: HomeAssistant) -> None:
|
||||
assert result2["type"] is FlowResultType.FORM
|
||||
assert result2["errors"] == {"base": "invalid_auth"}
|
||||
|
||||
doorbirdapi = _get_mock_doorbirdapi_return_values(info={"WIFI_MAC_ADDR": "macaddr"})
|
||||
doorbirdapi = get_mock_doorbird_api(info={"WIFI_MAC_ADDR": "macaddr"})
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.doorbird.config_flow.DoorBird",
|
||||
|
35
tests/components/doorbird/test_init.py
Normal file
35
tests/components/doorbird/test_init.py
Normal file
@ -0,0 +1,35 @@
|
||||
"""Test DoorBird init."""
|
||||
|
||||
from collections.abc import Callable, Coroutine
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.doorbird.const import DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import mock_unauthorized_exception
|
||||
from .conftest import MockDoorbirdEntry
|
||||
|
||||
|
||||
async def test_basic_setup(
|
||||
doorbird_mocker: Callable[[], Coroutine[Any, Any, MockDoorbirdEntry]],
|
||||
) -> None:
|
||||
"""Test basic setup."""
|
||||
doorbird_entry = await doorbird_mocker()
|
||||
entry = doorbird_entry.entry
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
|
||||
|
||||
async def test_auth_fails(
|
||||
hass: HomeAssistant,
|
||||
doorbird_mocker: Callable[[], Coroutine[Any, Any, MockDoorbirdEntry]],
|
||||
) -> None:
|
||||
"""Test basic setup with an auth failure."""
|
||||
doorbird_entry = await doorbird_mocker(
|
||||
info_side_effect=mock_unauthorized_exception()
|
||||
)
|
||||
entry = doorbird_entry.entry
|
||||
assert entry.state is ConfigEntryState.SETUP_ERROR
|
||||
flows = hass.config_entries.flow.async_progress(DOMAIN)
|
||||
assert len(flows) == 1
|
||||
assert flows[0]["step_id"] == "reauth_confirm"
|
Loading…
x
Reference in New Issue
Block a user