Nice G.O. code quality improvements (#124319)
* Bring Nice G.O. up to platinum * Switch to listen in coordinator * Tests * Remove parallel updates from coordinator * Unsub from events on config entry unload * Detect WS disconnection * Tests * Fix tests * Set unsub to None after unsubbing * Wait 5 seconds before setting update error to prevent excessive errors * Tweaks * More tweaks * Tweaks part 2 * Potential test for hass stopping * Improve reconnect handling and test on Homeassistant stop event * Move event handler to entry init * Patch const instead of asyncio.sleep --------- Co-authored-by: jbouwh <jan@jbsoft.nl>
This commit is contained in:
parent
741add0666
commit
cd3059aa14
7 changed files with 221 additions and 28 deletions
|
@ -1,7 +1,8 @@
|
|||
"""Test Nice G.O. init."""
|
||||
|
||||
import asyncio
|
||||
from datetime import timedelta
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
from nice_go import ApiError, AuthFailedError, Barrier, BarrierState
|
||||
|
@ -10,8 +11,8 @@ from syrupy.assertion import SnapshotAssertion
|
|||
|
||||
from homeassistant.components.nice_go.const import DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, Platform
|
||||
from homeassistant.core import Event, HomeAssistant, callback
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
|
||||
from . import setup_integration
|
||||
|
@ -209,11 +210,11 @@ async def test_on_data_none_parsed(
|
|||
) -> None:
|
||||
"""Test on data with None parsed."""
|
||||
|
||||
mock_nice_go.event = MagicMock()
|
||||
mock_nice_go.listen = MagicMock()
|
||||
|
||||
await setup_integration(hass, mock_config_entry, [Platform.COVER])
|
||||
|
||||
await mock_nice_go.event.call_args[0][0](
|
||||
await mock_nice_go.listen.call_args_list[1][0][1](
|
||||
{
|
||||
"data": {
|
||||
"devicesStatesUpdateFeed": {
|
||||
|
@ -243,18 +244,74 @@ async def test_on_connected(
|
|||
) -> None:
|
||||
"""Test on connected."""
|
||||
|
||||
mock_nice_go.event = MagicMock()
|
||||
mock_nice_go.listen = MagicMock()
|
||||
|
||||
await setup_integration(hass, mock_config_entry, [Platform.COVER])
|
||||
|
||||
assert mock_nice_go.event.call_count == 2
|
||||
assert mock_nice_go.listen.call_count == 3
|
||||
|
||||
mock_nice_go.subscribe = AsyncMock()
|
||||
await mock_nice_go.event.call_args_list[0][0][0]()
|
||||
await mock_nice_go.listen.call_args_list[0][0][1]()
|
||||
|
||||
assert mock_nice_go.subscribe.call_count == 1
|
||||
|
||||
|
||||
async def test_on_connection_lost(
|
||||
hass: HomeAssistant,
|
||||
mock_nice_go: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test on connection lost."""
|
||||
|
||||
mock_nice_go.listen = MagicMock()
|
||||
|
||||
await setup_integration(hass, mock_config_entry, [Platform.COVER])
|
||||
|
||||
assert mock_nice_go.listen.call_count == 3
|
||||
|
||||
with patch("homeassistant.components.nice_go.coordinator.RECONNECT_DELAY", 0):
|
||||
await mock_nice_go.listen.call_args_list[2][0][1](
|
||||
{"exception": ValueError("test")}
|
||||
)
|
||||
|
||||
assert hass.states.get("cover.test_garage_1").state == "unavailable"
|
||||
|
||||
# Now fire connected
|
||||
|
||||
mock_nice_go.subscribe = AsyncMock()
|
||||
|
||||
await mock_nice_go.listen.call_args_list[0][0][1]()
|
||||
|
||||
assert mock_nice_go.subscribe.call_count == 1
|
||||
|
||||
assert hass.states.get("cover.test_garage_1").state == "closed"
|
||||
|
||||
|
||||
async def test_on_connection_lost_reconnect(
|
||||
hass: HomeAssistant,
|
||||
mock_nice_go: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test on connection lost with reconnect."""
|
||||
|
||||
mock_nice_go.listen = MagicMock()
|
||||
|
||||
await setup_integration(hass, mock_config_entry, [Platform.COVER])
|
||||
|
||||
assert mock_nice_go.listen.call_count == 3
|
||||
|
||||
assert hass.states.get("cover.test_garage_1").state == "closed"
|
||||
|
||||
with patch("homeassistant.components.nice_go.coordinator.RECONNECT_DELAY", 0):
|
||||
await mock_nice_go.listen.call_args_list[2][0][1](
|
||||
{"exception": ValueError("test")}
|
||||
)
|
||||
|
||||
assert hass.states.get("cover.test_garage_1").state == "unavailable"
|
||||
|
||||
|
||||
async def test_no_connection_state(
|
||||
hass: HomeAssistant,
|
||||
mock_nice_go: AsyncMock,
|
||||
|
@ -262,13 +319,13 @@ async def test_no_connection_state(
|
|||
) -> None:
|
||||
"""Test parsing barrier with no connection state."""
|
||||
|
||||
mock_nice_go.event = MagicMock()
|
||||
mock_nice_go.listen = MagicMock()
|
||||
|
||||
await setup_integration(hass, mock_config_entry, [Platform.COVER])
|
||||
|
||||
assert mock_nice_go.event.call_count == 2
|
||||
assert mock_nice_go.listen.call_count == 3
|
||||
|
||||
await mock_nice_go.event.call_args[0][0](
|
||||
await mock_nice_go.listen.call_args_list[1][0][1](
|
||||
{
|
||||
"data": {
|
||||
"devicesStatesUpdateFeed": {
|
||||
|
@ -286,3 +343,65 @@ async def test_no_connection_state(
|
|||
)
|
||||
|
||||
assert hass.states.get("cover.test_garage_1").state == "unavailable"
|
||||
|
||||
|
||||
async def test_connection_attempts_exhausted(
|
||||
hass: HomeAssistant,
|
||||
mock_nice_go: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test connection attempts exhausted."""
|
||||
|
||||
mock_nice_go.connect.side_effect = ApiError
|
||||
|
||||
with (
|
||||
patch("homeassistant.components.nice_go.coordinator.RECONNECT_ATTEMPTS", 1),
|
||||
patch("homeassistant.components.nice_go.coordinator.RECONNECT_DELAY", 0),
|
||||
):
|
||||
await setup_integration(hass, mock_config_entry, [Platform.COVER])
|
||||
|
||||
assert "API error" in caplog.text
|
||||
assert "Error requesting Nice G.O. data" in caplog.text
|
||||
|
||||
|
||||
async def test_reconnect_hass_stopping(
|
||||
hass: HomeAssistant,
|
||||
mock_nice_go: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test reconnect with hass stopping."""
|
||||
|
||||
mock_nice_go.listen = MagicMock()
|
||||
mock_nice_go.connect.side_effect = ApiError
|
||||
|
||||
wait_for_hass = asyncio.Event()
|
||||
|
||||
@callback
|
||||
def _async_ha_stop(event: Event) -> None:
|
||||
"""Stop reconnecting if hass is stopping."""
|
||||
wait_for_hass.set()
|
||||
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _async_ha_stop)
|
||||
|
||||
with (
|
||||
patch("homeassistant.components.nice_go.coordinator.RECONNECT_DELAY", 0.1),
|
||||
patch("homeassistant.components.nice_go.coordinator.RECONNECT_ATTEMPTS", 20),
|
||||
):
|
||||
await setup_integration(hass, mock_config_entry, [Platform.COVER])
|
||||
await hass.async_block_till_done()
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
|
||||
await wait_for_hass.wait()
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
assert mock_nice_go.connect.call_count < 10
|
||||
|
||||
assert len(hass._background_tasks) == 0
|
||||
|
||||
assert "API error" in caplog.text
|
||||
assert (
|
||||
"Failed to connect to the websocket, reconnect attempts exhausted"
|
||||
not in caplog.text
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue