Refactor Linear tests (#116336)

This commit is contained in:
Joost Lekkerkerker 2024-05-14 20:47:14 +02:00 committed by GitHub
parent add6ffaf70
commit d88851a85a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 621 additions and 531 deletions

View File

@ -1 +1,22 @@
"""Tests for the Linear Garage Door integration.""" """Tests for the Linear Garage Door integration."""
from unittest.mock import patch
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
async def setup_integration(
hass: HomeAssistant, config_entry: MockConfigEntry, platforms: list[Platform]
) -> None:
"""Fixture for setting up the component."""
config_entry.add_to_hass(hass)
with patch(
"homeassistant.components.linear_garage_door.PLATFORMS",
platforms,
):
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()

View File

@ -0,0 +1,67 @@
"""Common fixtures for the Linear Garage Door tests."""
from collections.abc import Generator
from unittest.mock import AsyncMock, patch
import pytest
from homeassistant.components.linear_garage_door import DOMAIN
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from tests.common import (
MockConfigEntry,
load_json_array_fixture,
load_json_object_fixture,
)
@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock, None, None]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.linear_garage_door.async_setup_entry",
return_value=True,
) as mock_setup_entry:
yield mock_setup_entry
@pytest.fixture
def mock_linear() -> Generator[AsyncMock, None, None]:
"""Mock a Linear Garage Door client."""
with (
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear",
autospec=True,
) as mock_client,
patch(
"homeassistant.components.linear_garage_door.config_flow.Linear",
new=mock_client,
),
):
client = mock_client.return_value
client.login.return_value = True
client.get_devices.return_value = load_json_array_fixture(
"get_devices.json", DOMAIN
)
client.get_sites.return_value = load_json_array_fixture(
"get_sites.json", DOMAIN
)
device_states = load_json_object_fixture("get_device_state.json", DOMAIN)
client.get_device_state.side_effect = lambda device_id: device_states[device_id]
yield client
@pytest.fixture
def mock_config_entry() -> MockConfigEntry:
"""Mock a config entry."""
return MockConfigEntry(
domain=DOMAIN,
entry_id="acefdd4b3a4a0911067d1cf51414201e",
title="test-site-name",
data={
CONF_EMAIL: "test-email",
CONF_PASSWORD: "test-password",
"site_id": "test-site-id",
"device_id": "test-uuid",
},
)

View File

@ -0,0 +1,42 @@
{
"test1": {
"GDO": {
"Open_B": "true",
"Open_P": "100"
},
"Light": {
"On_B": "true",
"On_P": "100"
}
},
"test2": {
"GDO": {
"Open_B": "false",
"Open_P": "0"
},
"Light": {
"On_B": "false",
"On_P": "0"
}
},
"test3": {
"GDO": {
"Open_B": "false",
"Opening_P": "0"
},
"Light": {
"On_B": "false",
"On_P": "0"
}
},
"test4": {
"GDO": {
"Open_B": "true",
"Opening_P": "100"
},
"Light": {
"On_B": "true",
"On_P": "100"
}
}
}

View File

@ -0,0 +1,42 @@
{
"test1": {
"GDO": {
"Open_B": "true",
"Opening_P": "100"
},
"Light": {
"On_B": "true",
"On_P": "100"
}
},
"test2": {
"GDO": {
"Open_B": "false",
"Opening_P": "0"
},
"Light": {
"On_B": "false",
"On_P": "0"
}
},
"test3": {
"GDO": {
"Open_B": "false",
"Opening_P": "0"
},
"Light": {
"On_B": "false",
"On_P": "0"
}
},
"test4": {
"GDO": {
"Open_B": "true",
"Opening_P": "100"
},
"Light": {
"On_B": "true",
"On_P": "100"
}
}
}

View File

@ -0,0 +1,22 @@
[
{
"id": "test1",
"name": "Test Garage 1",
"subdevices": ["GDO", "Light"]
},
{
"id": "test2",
"name": "Test Garage 2",
"subdevices": ["GDO", "Light"]
},
{
"id": "test3",
"name": "Test Garage 3",
"subdevices": ["GDO", "Light"]
},
{
"id": "test4",
"name": "Test Garage 4",
"subdevices": ["GDO", "Light"]
}
]

View File

@ -0,0 +1 @@
[{ "id": "test-site-id", "name": "test-site-name" }]

View File

@ -0,0 +1,193 @@
# serializer version: 1
# name: test_covers[cover.test_garage_1-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'cover',
'entity_category': None,
'entity_id': 'cover.test_garage_1',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <CoverDeviceClass.GARAGE: 'garage'>,
'original_icon': None,
'original_name': None,
'platform': 'linear_garage_door',
'previous_unique_id': None,
'supported_features': <CoverEntityFeature: 3>,
'translation_key': None,
'unique_id': 'test1-GDO',
'unit_of_measurement': None,
})
# ---
# name: test_covers[cover.test_garage_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'garage',
'friendly_name': 'Test Garage 1',
'supported_features': <CoverEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'cover.test_garage_1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'open',
})
# ---
# name: test_covers[cover.test_garage_2-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'cover',
'entity_category': None,
'entity_id': 'cover.test_garage_2',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <CoverDeviceClass.GARAGE: 'garage'>,
'original_icon': None,
'original_name': None,
'platform': 'linear_garage_door',
'previous_unique_id': None,
'supported_features': <CoverEntityFeature: 3>,
'translation_key': None,
'unique_id': 'test2-GDO',
'unit_of_measurement': None,
})
# ---
# name: test_covers[cover.test_garage_2-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'garage',
'friendly_name': 'Test Garage 2',
'supported_features': <CoverEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'cover.test_garage_2',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'closed',
})
# ---
# name: test_covers[cover.test_garage_3-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'cover',
'entity_category': None,
'entity_id': 'cover.test_garage_3',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <CoverDeviceClass.GARAGE: 'garage'>,
'original_icon': None,
'original_name': None,
'platform': 'linear_garage_door',
'previous_unique_id': None,
'supported_features': <CoverEntityFeature: 3>,
'translation_key': None,
'unique_id': 'test3-GDO',
'unit_of_measurement': None,
})
# ---
# name: test_covers[cover.test_garage_3-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'garage',
'friendly_name': 'Test Garage 3',
'supported_features': <CoverEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'cover.test_garage_3',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'opening',
})
# ---
# name: test_covers[cover.test_garage_4-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'cover',
'entity_category': None,
'entity_id': 'cover.test_garage_4',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <CoverDeviceClass.GARAGE: 'garage'>,
'original_icon': None,
'original_name': None,
'platform': 'linear_garage_door',
'previous_unique_id': None,
'supported_features': <CoverEntityFeature: 3>,
'translation_key': None,
'unique_id': 'test4-GDO',
'unit_of_measurement': None,
})
# ---
# name: test_covers[cover.test_garage_4-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'garage',
'friendly_name': 'Test Garage 4',
'supported_features': <CoverEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'cover.test_garage_4',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'closing',
})
# ---

View File

@ -71,7 +71,7 @@
'pref_disable_new_entities': False, 'pref_disable_new_entities': False,
'pref_disable_polling': False, 'pref_disable_polling': False,
'source': 'user', 'source': 'user',
'title': 'Mock Title', 'title': 'test-site-name',
'unique_id': None, 'unique_id': None,
'version': 1, 'version': 1,
}), }),

View File

@ -1,180 +1,141 @@
"""Test the Linear Garage Door config flow.""" """Test the Linear Garage Door config flow."""
from unittest.mock import patch from unittest.mock import AsyncMock, patch
from linear_garage_door.errors import InvalidLoginError from linear_garage_door.errors import InvalidLoginError
import pytest
from homeassistant import config_entries
from homeassistant.components.linear_garage_door.const import DOMAIN from homeassistant.components.linear_garage_door.const import DOMAIN
from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_USER
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType from homeassistant.data_entry_flow import FlowResultType
from .util import async_init_integration from tests.common import MockConfigEntry
async def test_form(hass: HomeAssistant) -> None: async def test_form(
hass: HomeAssistant, mock_linear: AsyncMock, mock_setup_entry: AsyncMock
) -> None:
"""Test we get the form.""" """Test we get the form."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER} DOMAIN, context={"source": SOURCE_USER}
) )
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["errors"] is None assert not result["errors"]
with ( with patch(
patch( "uuid.uuid4",
"homeassistant.components.linear_garage_door.config_flow.Linear.login", return_value="test-uuid",
return_value=True,
),
patch(
"homeassistant.components.linear_garage_door.config_flow.Linear.get_sites",
return_value=[{"id": "test-site-id", "name": "test-site-name"}],
),
patch(
"homeassistant.components.linear_garage_door.config_flow.Linear.close",
return_value=None,
),
patch(
"uuid.uuid4",
return_value="test-uuid",
),
): ):
result2 = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{ {
"email": "test-email", CONF_EMAIL: "test-email",
"password": "test-password", CONF_PASSWORD: "test-password",
}, },
) )
await hass.async_block_till_done() await hass.async_block_till_done()
with patch( result = await hass.config_entries.flow.async_configure(
"homeassistant.components.linear_garage_door.async_setup_entry", result["flow_id"], {"site": "test-site-id"}
return_value=True, )
) as mock_setup_entry: await hass.async_block_till_done()
result3 = await hass.config_entries.flow.async_configure(
result2["flow_id"], {"site": "test-site-id"}
)
await hass.async_block_till_done()
assert result3["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result3["title"] == "test-site-name" assert result["title"] == "test-site-name"
assert result3["data"] == { assert result["data"] == {
"email": "test-email", CONF_EMAIL: "test-email",
"password": "test-password", CONF_PASSWORD: "test-password",
"site_id": "test-site-id", "site_id": "test-site-id",
"device_id": "test-uuid", "device_id": "test-uuid",
} }
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
async def test_reauth(hass: HomeAssistant) -> None: async def test_reauth(
hass: HomeAssistant,
mock_linear: AsyncMock,
mock_setup_entry: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test reauthentication.""" """Test reauthentication."""
mock_config_entry.add_to_hass(hass)
with patch(
"homeassistant.components.linear_garage_door.async_setup_entry",
return_value=True,
):
entry = await async_init_integration(hass)
result1 = await hass.config_entries.flow.async_init(
DOMAIN,
context={
"source": config_entries.SOURCE_REAUTH,
"entry_id": entry.entry_id,
"title_placeholders": {"name": entry.title},
"unique_id": entry.unique_id,
},
data=entry.data,
)
assert result1["type"] is FlowResultType.FORM
assert result1["step_id"] == "user"
with (
patch(
"homeassistant.components.linear_garage_door.config_flow.Linear.login",
return_value=True,
),
patch(
"homeassistant.components.linear_garage_door.config_flow.Linear.get_sites",
return_value=[{"id": "test-site-id", "name": "test-site-name"}],
),
patch(
"homeassistant.components.linear_garage_door.config_flow.Linear.close",
return_value=None,
),
patch(
"uuid.uuid4",
return_value="test-uuid",
),
):
result2 = await hass.config_entries.flow.async_configure(
result1["flow_id"],
{
"email": "new-email",
"password": "new-password",
},
)
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.ABORT
assert result2["reason"] == "reauth_successful"
entries = hass.config_entries.async_entries()
assert len(entries) == 1
assert entries[0].data == {
"email": "new-email",
"password": "new-password",
"site_id": "test-site-id",
"device_id": "test-uuid",
}
async def test_form_invalid_login(hass: HomeAssistant) -> None:
"""Test we handle invalid auth."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with (
patch(
"homeassistant.components.linear_garage_door.config_flow.Linear.login",
side_effect=InvalidLoginError,
),
patch(
"homeassistant.components.linear_garage_door.config_flow.Linear.close",
return_value=None,
),
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"email": "test-email",
"password": "test-password",
},
)
assert result2["type"] is FlowResultType.FORM
assert result2["errors"] == {"base": "invalid_auth"}
async def test_form_exception(hass: HomeAssistant) -> None:
"""Test we handle invalid auth."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
context={"source": config_entries.SOURCE_USER}, context={
"source": SOURCE_REAUTH,
"entry_id": mock_config_entry.entry_id,
"title_placeholders": {"name": mock_config_entry.title},
"unique_id": mock_config_entry.unique_id,
},
data=mock_config_entry.data,
) )
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
with patch( with patch(
"homeassistant.components.linear_garage_door.config_flow.Linear.login", "uuid.uuid4",
side_effect=Exception, return_value="test-uuid",
): ):
result2 = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{ {
"email": "test-email", CONF_EMAIL: "new-email",
"password": "test-password", CONF_PASSWORD: "new-password",
}, },
) )
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.ABORT
assert result2["errors"] == {"base": "unknown"} assert result["reason"] == "reauth_successful"
assert mock_config_entry.data == {
CONF_EMAIL: "new-email",
CONF_PASSWORD: "new-password",
"site_id": "test-site-id",
"device_id": "test-uuid",
}
@pytest.mark.parametrize(
("side_effect", "expected_error"),
[(InvalidLoginError, "invalid_auth"), (Exception, "unknown")],
)
async def test_form_exceptions(
hass: HomeAssistant,
mock_linear: AsyncMock,
mock_setup_entry: AsyncMock,
side_effect: Exception,
expected_error: str,
) -> None:
"""Test we handle invalid auth."""
mock_linear.login.side_effect = side_effect
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_EMAIL: "test-email",
CONF_PASSWORD: "test-password",
},
)
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {"base": expected_error}
mock_linear.login.side_effect = None
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_EMAIL: "test-email",
CONF_PASSWORD: "test-password",
},
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"site": "test-site-id"}
)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.CREATE_ENTRY

View File

@ -1,73 +0,0 @@
"""Test data update coordinator for Linear Garage Door."""
from unittest.mock import patch
from linear_garage_door.errors import InvalidLoginError
from homeassistant.components.linear_garage_door.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
async def test_invalid_password(
hass: HomeAssistant,
) -> None:
"""Test invalid password."""
config_entry = MockConfigEntry(
domain=DOMAIN,
data={
"email": "test-email",
"password": "test-password",
"site_id": "test-site-id",
"device_id": "test-uuid",
},
)
config_entry.add_to_hass(hass)
with patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.login",
side_effect=InvalidLoginError(
"Login provided is invalid, please check the email and password"
),
):
assert not await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entries = hass.config_entries.async_entries(DOMAIN)
assert entries
assert len(entries) == 1
assert entries[0].state is ConfigEntryState.SETUP_ERROR
flows = hass.config_entries.flow.async_progress_by_handler(DOMAIN)
assert flows
assert len(flows) == 1
assert flows[0]["context"]["source"] == "reauth"
async def test_invalid_login(
hass: HomeAssistant,
) -> None:
"""Test invalid login."""
config_entry = MockConfigEntry(
domain=DOMAIN,
data={
"email": "test-email",
"password": "test-password",
"site_id": "test-site-id",
"device_id": "test-uuid",
},
)
config_entry.add_to_hass(hass)
with patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.login",
side_effect=InvalidLoginError("Some other error"),
):
assert not await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entries = hass.config_entries.async_entries(DOMAIN)
assert entries
assert len(entries) == 1
assert entries[0].state is ConfigEntryState.SETUP_RETRY

View File

@ -1,221 +1,124 @@
"""Test Linear Garage Door cover.""" """Test Linear Garage Door cover."""
from datetime import timedelta from datetime import timedelta
from unittest.mock import patch from unittest.mock import AsyncMock
from freezegun.api import FrozenDateTimeFactory
from syrupy import SnapshotAssertion
from homeassistant.components.cover import ( from homeassistant.components.cover import (
DOMAIN as COVER_DOMAIN, DOMAIN as COVER_DOMAIN,
SERVICE_CLOSE_COVER, SERVICE_CLOSE_COVER,
SERVICE_OPEN_COVER, SERVICE_OPEN_COVER,
)
from homeassistant.components.linear_garage_door import DOMAIN
from homeassistant.const import (
ATTR_ENTITY_ID,
STATE_CLOSED, STATE_CLOSED,
STATE_CLOSING, STATE_CLOSING,
STATE_OPEN, STATE_OPEN,
STATE_OPENING, STATE_OPENING,
Platform,
) )
from homeassistant.components.linear_garage_door.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
import homeassistant.util.dt as dt_util from homeassistant.helpers import entity_registry as er
from .util import async_init_integration from . import setup_integration
from tests.common import async_fire_time_changed from tests.common import (
MockConfigEntry,
async_fire_time_changed,
load_json_object_fixture,
snapshot_platform,
)
async def test_data(hass: HomeAssistant) -> None: async def test_covers(
hass: HomeAssistant,
mock_linear: AsyncMock,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test that data gets parsed and returned appropriately.""" """Test that data gets parsed and returned appropriately."""
await async_init_integration(hass) await setup_integration(hass, mock_config_entry, [Platform.COVER])
assert hass.data[DOMAIN] await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
entries = hass.config_entries.async_entries(DOMAIN)
assert entries
assert len(entries) == 1
assert entries[0].state is ConfigEntryState.LOADED
assert hass.states.get("cover.test_garage_1").state == STATE_OPEN
assert hass.states.get("cover.test_garage_2").state == STATE_CLOSED
assert hass.states.get("cover.test_garage_3").state == STATE_OPENING
assert hass.states.get("cover.test_garage_4").state == STATE_CLOSING
async def test_open_cover(hass: HomeAssistant) -> None: async def test_open_cover(
hass: HomeAssistant, mock_linear: AsyncMock, mock_config_entry: MockConfigEntry
) -> None:
"""Test that opening the cover works as intended.""" """Test that opening the cover works as intended."""
await async_init_integration(hass) await setup_integration(hass, mock_config_entry, [Platform.COVER])
with patch( await hass.services.async_call(
"homeassistant.components.linear_garage_door.coordinator.Linear.operate_device" COVER_DOMAIN,
) as operate_device: SERVICE_OPEN_COVER,
await hass.services.async_call( {ATTR_ENTITY_ID: "cover.test_garage_1"},
COVER_DOMAIN, blocking=True,
SERVICE_OPEN_COVER, )
{ATTR_ENTITY_ID: "cover.test_garage_1"},
blocking=True,
)
assert operate_device.call_count == 0 assert mock_linear.operate_device.call_count == 0
with ( await hass.services.async_call(
patch( COVER_DOMAIN,
"homeassistant.components.linear_garage_door.coordinator.Linear.login", SERVICE_OPEN_COVER,
return_value=True, {ATTR_ENTITY_ID: "cover.test_garage_2"},
), blocking=True,
patch( )
"homeassistant.components.linear_garage_door.coordinator.Linear.operate_device",
return_value=None,
) as operate_device,
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.close",
return_value=True,
),
):
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_OPEN_COVER,
{ATTR_ENTITY_ID: "cover.test_garage_2"},
blocking=True,
)
assert operate_device.call_count == 1 assert mock_linear.operate_device.call_count == 1
with (
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.login",
return_value=True,
),
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.get_devices",
return_value=[
{
"id": "test1",
"name": "Test Garage 1",
"subdevices": ["GDO", "Light"],
},
{
"id": "test2",
"name": "Test Garage 2",
"subdevices": ["GDO", "Light"],
},
],
),
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.get_device_state",
side_effect=lambda id: {
"test1": {
"GDO": {"Open_B": "true", "Open_P": "100"},
"Light": {"On_B": "true", "On_P": "100"},
},
"test2": {
"GDO": {"Open_B": "false", "Opening_P": "0"},
"Light": {"On_B": "false", "On_P": "0"},
},
"test3": {
"GDO": {"Open_B": "false", "Opening_P": "0"},
"Light": {"On_B": "false", "On_P": "0"},
},
"test4": {
"GDO": {"Open_B": "true", "Opening_P": "100"},
"Light": {"On_B": "true", "On_P": "100"},
},
}[id],
),
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.close",
return_value=True,
),
):
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=60))
await hass.async_block_till_done()
assert hass.states.get("cover.test_garage_2").state == STATE_OPENING
async def test_close_cover(hass: HomeAssistant) -> None: async def test_close_cover(
hass: HomeAssistant, mock_linear: AsyncMock, mock_config_entry: MockConfigEntry
) -> None:
"""Test that closing the cover works as intended.""" """Test that closing the cover works as intended."""
await async_init_integration(hass) await setup_integration(hass, mock_config_entry, [Platform.COVER])
with patch( await hass.services.async_call(
"homeassistant.components.linear_garage_door.coordinator.Linear.operate_device" COVER_DOMAIN,
) as operate_device: SERVICE_CLOSE_COVER,
await hass.services.async_call( {ATTR_ENTITY_ID: "cover.test_garage_2"},
COVER_DOMAIN, blocking=True,
SERVICE_CLOSE_COVER, )
{ATTR_ENTITY_ID: "cover.test_garage_2"},
blocking=True,
)
assert operate_device.call_count == 0 assert mock_linear.operate_device.call_count == 0
with ( await hass.services.async_call(
patch( COVER_DOMAIN,
"homeassistant.components.linear_garage_door.coordinator.Linear.login", SERVICE_CLOSE_COVER,
return_value=True, {ATTR_ENTITY_ID: "cover.test_garage_1"},
), blocking=True,
patch( )
"homeassistant.components.linear_garage_door.coordinator.Linear.operate_device",
return_value=None,
) as operate_device,
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.close",
return_value=True,
),
):
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_CLOSE_COVER,
{ATTR_ENTITY_ID: "cover.test_garage_1"},
blocking=True,
)
assert operate_device.call_count == 1 assert mock_linear.operate_device.call_count == 1
with (
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.login", async def test_update_cover_state(
return_value=True, hass: HomeAssistant,
), mock_linear: AsyncMock,
patch( mock_config_entry: MockConfigEntry,
"homeassistant.components.linear_garage_door.coordinator.Linear.get_devices", freezer: FrozenDateTimeFactory,
return_value=[ ) -> None:
{ """Test that closing the cover works as intended."""
"id": "test1",
"name": "Test Garage 1", await setup_integration(hass, mock_config_entry, [Platform.COVER])
"subdevices": ["GDO", "Light"],
}, assert hass.states.get("cover.test_garage_1").state == STATE_OPEN
{ assert hass.states.get("cover.test_garage_2").state == STATE_CLOSED
"id": "test2",
"name": "Test Garage 2", device_states = load_json_object_fixture("get_device_state_1.json", DOMAIN)
"subdevices": ["GDO", "Light"], mock_linear.get_device_state.side_effect = lambda device_id: device_states[
}, device_id
], ]
),
patch( freezer.tick(timedelta(seconds=60))
"homeassistant.components.linear_garage_door.coordinator.Linear.get_device_state", async_fire_time_changed(hass)
side_effect=lambda id: {
"test1": {
"GDO": {"Open_B": "true", "Opening_P": "100"},
"Light": {"On_B": "true", "On_P": "100"},
},
"test2": {
"GDO": {"Open_B": "false", "Open_P": "0"},
"Light": {"On_B": "false", "On_P": "0"},
},
"test3": {
"GDO": {"Open_B": "false", "Opening_P": "0"},
"Light": {"On_B": "false", "On_P": "0"},
},
"test4": {
"GDO": {"Open_B": "true", "Opening_P": "100"},
"Light": {"On_B": "true", "On_P": "100"},
},
}[id],
),
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.close",
return_value=True,
),
):
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=60))
await hass.async_block_till_done()
assert hass.states.get("cover.test_garage_1").state == STATE_CLOSING assert hass.states.get("cover.test_garage_1").state == STATE_CLOSING
assert hass.states.get("cover.test_garage_2").state == STATE_OPENING

View File

@ -1,11 +1,14 @@
"""Test diagnostics of Linear Garage Door.""" """Test diagnostics of Linear Garage Door."""
from unittest.mock import AsyncMock
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from .util import async_init_integration from . import setup_integration
from tests.common import MockConfigEntry
from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
@ -14,8 +17,12 @@ async def test_entry_diagnostics(
hass: HomeAssistant, hass: HomeAssistant,
hass_client: ClientSessionGenerator, hass_client: ClientSessionGenerator,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
mock_linear: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None: ) -> None:
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
entry = await async_init_integration(hass) await setup_integration(hass, mock_config_entry, [])
result = await get_diagnostics_for_config_entry(hass, hass_client, entry) result = await get_diagnostics_for_config_entry(
hass, hass_client, mock_config_entry
)
assert result == snapshot assert result == snapshot

View File

@ -1,64 +1,52 @@
"""Test Linear Garage Door init.""" """Test Linear Garage Door init."""
from unittest.mock import patch from unittest.mock import AsyncMock
from linear_garage_door import InvalidLoginError
import pytest
from homeassistant.components.linear_garage_door.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
from tests.components.linear_garage_door import setup_integration
async def test_unload_entry(hass: HomeAssistant) -> None: async def test_unload_entry(
hass: HomeAssistant, mock_linear: AsyncMock, mock_config_entry: MockConfigEntry
) -> None:
"""Test the unload entry.""" """Test the unload entry."""
config_entry = MockConfigEntry(
domain=DOMAIN,
data={
"email": "test-email",
"password": "test-password",
"site_id": "test-site-id",
"device_id": "test-uuid",
},
)
config_entry.add_to_hass(hass)
with ( await setup_integration(hass, mock_config_entry, [])
patch( assert mock_config_entry.state is ConfigEntryState.LOADED
"homeassistant.components.linear_garage_door.coordinator.Linear.login",
return_value=True,
),
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.get_devices",
return_value=[
{"id": "test", "name": "Test Garage", "subdevices": ["GDO", "Light"]}
],
),
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.get_device_state",
return_value={
"GDO": {"Open_B": "true", "Open_P": "100"},
"Light": {"On_B": "true", "On_P": "10"},
},
),
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.close",
return_value=True,
),
):
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert hass.data[DOMAIN] await hass.config_entries.async_unload(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert mock_config_entry.state is ConfigEntryState.NOT_LOADED
entries = hass.config_entries.async_entries(DOMAIN)
assert entries
assert len(entries) == 1
assert entries[0].state is ConfigEntryState.LOADED
with patch( @pytest.mark.parametrize(
"homeassistant.components.linear_garage_door.coordinator.Linear.close", ("side_effect", "entry_state"),
return_value=True, [
): (
await hass.config_entries.async_unload(entries[0].entry_id) InvalidLoginError(
await hass.async_block_till_done() "Login provided is invalid, please check the email and password"
assert entries[0].state is ConfigEntryState.NOT_LOADED ),
ConfigEntryState.SETUP_ERROR,
),
(InvalidLoginError("Invalid login"), ConfigEntryState.SETUP_RETRY),
],
)
async def test_setup_failure(
hass: HomeAssistant,
mock_linear: AsyncMock,
mock_config_entry: MockConfigEntry,
side_effect: Exception,
entry_state: ConfigEntryState,
) -> None:
"""Test reauth trigger setup."""
mock_linear.login.side_effect = side_effect
await setup_integration(hass, mock_config_entry, [])
assert mock_config_entry.state == entry_state

View File

@ -1,84 +0,0 @@
"""Utilities for Linear Garage Door testing."""
from unittest.mock import patch
from homeassistant.components.linear_garage_door.const import DOMAIN
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
async def async_init_integration(hass: HomeAssistant) -> MockConfigEntry:
"""Initialize mock integration."""
config_entry = MockConfigEntry(
domain=DOMAIN,
entry_id="acefdd4b3a4a0911067d1cf51414201e",
data={
"email": "test-email",
"password": "test-password",
"site_id": "test-site-id",
"device_id": "test-uuid",
},
)
config_entry.add_to_hass(hass)
with (
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.login",
return_value=True,
),
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.get_devices",
return_value=[
{
"id": "test1",
"name": "Test Garage 1",
"subdevices": ["GDO", "Light"],
},
{
"id": "test2",
"name": "Test Garage 2",
"subdevices": ["GDO", "Light"],
},
{
"id": "test3",
"name": "Test Garage 3",
"subdevices": ["GDO", "Light"],
},
{
"id": "test4",
"name": "Test Garage 4",
"subdevices": ["GDO", "Light"],
},
],
),
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.get_device_state",
side_effect=lambda id: {
"test1": {
"GDO": {"Open_B": "true", "Open_P": "100"},
"Light": {"On_B": "true", "On_P": "100"},
},
"test2": {
"GDO": {"Open_B": "false", "Open_P": "0"},
"Light": {"On_B": "false", "On_P": "0"},
},
"test3": {
"GDO": {"Open_B": "false", "Opening_P": "0"},
"Light": {"On_B": "false", "On_P": "0"},
},
"test4": {
"GDO": {"Open_B": "true", "Opening_P": "100"},
"Light": {"On_B": "true", "On_P": "100"},
},
}[id],
),
patch(
"homeassistant.components.linear_garage_door.coordinator.Linear.close",
return_value=True,
),
):
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
return config_entry