From 8c4b07674619d9b042ddf9fd6e53911cd9173dcc Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Fri, 18 Oct 2024 16:00:42 +0200 Subject: [PATCH] Refactor rainforest_raven coordinator tests (#128591) * Refactor rainforest_raven tests * Remove assert * Cleanup freezer * Drop un-needed coordinator properties * Cleanup remaining coordinator tests * Improve * Revert _DEVICE_TIMEOUT * Ensure 100% coverage * Use async_fire_time_changed --- .../rainforest_raven/test_coordinator.py | 90 ------------------- .../components/rainforest_raven/test_init.py | 26 ++++++ .../rainforest_raven/test_sensor.py | 82 ++++++++++++++++- 3 files changed, 107 insertions(+), 91 deletions(-) delete mode 100644 tests/components/rainforest_raven/test_coordinator.py diff --git a/tests/components/rainforest_raven/test_coordinator.py b/tests/components/rainforest_raven/test_coordinator.py deleted file mode 100644 index dc29e95bbb5fd5..00000000000000 --- a/tests/components/rainforest_raven/test_coordinator.py +++ /dev/null @@ -1,90 +0,0 @@ -"""Tests for the Rainforest RAVEn data coordinator.""" - -import asyncio -import functools -from unittest.mock import AsyncMock - -from aioraven.device import RAVEnConnectionError -import pytest - -from homeassistant.components.rainforest_raven.coordinator import RAVEnDataCoordinator -from homeassistant.config_entries import ConfigEntryState -from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady - -from . import create_mock_entry - - -async def test_coordinator_cache_device( - hass: HomeAssistant, mock_device: AsyncMock -) -> None: - """Test that the device isn't re-opened for subsequent refreshes.""" - entry = create_mock_entry() - entry._async_set_state(hass, ConfigEntryState.SETUP_IN_PROGRESS, None) - coordinator = RAVEnDataCoordinator(hass, entry) - - await coordinator.async_config_entry_first_refresh() - assert mock_device.get_network_info.call_count == 1 - assert mock_device.open.call_count == 1 - - await coordinator.async_refresh() - assert mock_device.get_network_info.call_count == 2 - assert mock_device.open.call_count == 1 - - -async def test_coordinator_device_error_setup( - hass: HomeAssistant, mock_device: AsyncMock -) -> None: - """Test handling of a device error during initialization.""" - entry = create_mock_entry() - entry._async_set_state(hass, ConfigEntryState.SETUP_IN_PROGRESS, None) - coordinator = RAVEnDataCoordinator(hass, entry) - - mock_device.get_network_info.side_effect = RAVEnConnectionError - with pytest.raises(ConfigEntryNotReady): - await coordinator.async_config_entry_first_refresh() - - -async def test_coordinator_device_error_update( - hass: HomeAssistant, mock_device: AsyncMock -) -> None: - """Test handling of a device error during an update.""" - entry = create_mock_entry() - entry._async_set_state(hass, ConfigEntryState.SETUP_IN_PROGRESS, None) - coordinator = RAVEnDataCoordinator(hass, entry) - - await coordinator.async_config_entry_first_refresh() - assert coordinator.last_update_success is True - - mock_device.get_network_info.side_effect = RAVEnConnectionError - await coordinator.async_refresh() - assert coordinator.last_update_success is False - - -async def test_coordinator_device_timeout_update( - hass: HomeAssistant, mock_device: AsyncMock -) -> None: - """Test handling of a device timeout during an update.""" - entry = create_mock_entry() - entry._async_set_state(hass, ConfigEntryState.SETUP_IN_PROGRESS, None) - coordinator = RAVEnDataCoordinator(hass, entry) - - await coordinator.async_config_entry_first_refresh() - assert coordinator.last_update_success is True - - mock_device.get_network_info.side_effect = functools.partial(asyncio.sleep, 10) - await coordinator.async_refresh() - assert coordinator.last_update_success is False - - -async def test_coordinator_comm_error( - hass: HomeAssistant, mock_device: AsyncMock -) -> None: - """Test handling of an error parsing or reading raw device data.""" - entry = create_mock_entry() - entry._async_set_state(hass, ConfigEntryState.SETUP_IN_PROGRESS, None) - coordinator = RAVEnDataCoordinator(hass, entry) - - mock_device.synchronize.side_effect = RAVEnConnectionError - with pytest.raises(ConfigEntryNotReady): - await coordinator.async_config_entry_first_refresh() diff --git a/tests/components/rainforest_raven/test_init.py b/tests/components/rainforest_raven/test_init.py index a2237096fb6a1b..acd1f606a078a0 100644 --- a/tests/components/rainforest_raven/test_init.py +++ b/tests/components/rainforest_raven/test_init.py @@ -3,6 +3,7 @@ from unittest.mock import AsyncMock from aioraven.data import DeviceInfo as RAVenDeviceInfo +from aioraven.device import RAVEnConnectionError import pytest from syrupy.assertion import SnapshotAssertion @@ -55,3 +56,28 @@ async def test_device_registry( entries = dr.async_entries_for_config_entry(device_registry, entry.entry_id) assert len(entries) == device_count assert entries == snapshot + + +async def test_synchronize_error(hass: HomeAssistant, mock_device: AsyncMock) -> None: + """Test handling of an error parsing or reading raw device data.""" + entry = create_mock_entry() + entry.add_to_hass(hass) + + mock_device.synchronize.side_effect = RAVEnConnectionError + + await hass.config_entries.async_setup(entry.entry_id) + + assert entry.state is ConfigEntryState.SETUP_RETRY + + +async def test_get_network_info_error( + hass: HomeAssistant, mock_device: AsyncMock +) -> None: + """Test handling of a device error during initialization.""" + entry = create_mock_entry() + entry.add_to_hass(hass) + + mock_device.get_network_info.side_effect = RAVEnConnectionError + await hass.config_entries.async_setup(entry.entry_id) + + assert entry.state is ConfigEntryState.SETUP_RETRY diff --git a/tests/components/rainforest_raven/test_sensor.py b/tests/components/rainforest_raven/test_sensor.py index 8d66ef2074bc16..2319b628374397 100644 --- a/tests/components/rainforest_raven/test_sensor.py +++ b/tests/components/rainforest_raven/test_sensor.py @@ -1,12 +1,20 @@ """Tests for the Rainforest RAVEn sensors.""" +from datetime import timedelta +from unittest.mock import AsyncMock + +from aioraven.device import RAVEnConnectionError +from freezegun.api import FrozenDateTimeFactory import pytest from syrupy.assertion import SnapshotAssertion +from homeassistant.const import STATE_UNAVAILABLE from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er -from tests.common import MockConfigEntry, snapshot_platform +from .const import NETWORK_INFO + +from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform @pytest.mark.usefixtures("mock_entry") @@ -20,3 +28,75 @@ async def test_sensors( assert len(hass.states.async_all()) == 5 await snapshot_platform(hass, entity_registry, snapshot, mock_entry.entry_id) + + +@pytest.mark.usefixtures("mock_entry") +async def test_device_update_error( + hass: HomeAssistant, + mock_device: AsyncMock, + freezer: FrozenDateTimeFactory, +) -> None: + """Test handling of a device error during an update.""" + mock_device.get_network_info.side_effect = (RAVEnConnectionError, NETWORK_INFO) + + states = hass.states.async_all() + assert len(states) == 5 + assert all(state.state != STATE_UNAVAILABLE for state in states) + + freezer.tick(timedelta(seconds=60)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + states = hass.states.async_all() + assert len(states) == 5 + assert all(state.state == STATE_UNAVAILABLE for state in states) + + freezer.tick(timedelta(seconds=60)) + async_fire_time_changed(hass) + + states = hass.states.async_all() + assert len(states) == 5 + assert all(state.state != STATE_UNAVAILABLE for state in states) + + +@pytest.mark.usefixtures("mock_entry") +async def test_device_update_timeout( + hass: HomeAssistant, mock_device: AsyncMock, freezer: FrozenDateTimeFactory +) -> None: + """Test handling of a device timeout during an update.""" + mock_device.get_network_info.side_effect = (TimeoutError, NETWORK_INFO) + + states = hass.states.async_all() + assert len(states) == 5 + assert all(state.state != STATE_UNAVAILABLE for state in states) + + freezer.tick(timedelta(seconds=60)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + states = hass.states.async_all() + assert len(states) == 5 + assert all(state.state == STATE_UNAVAILABLE for state in states) + + freezer.tick(timedelta(seconds=60)) + async_fire_time_changed(hass) + + states = hass.states.async_all() + assert len(states) == 5 + assert all(state.state != STATE_UNAVAILABLE for state in states) + + +@pytest.mark.usefixtures("mock_entry") +async def test_device_cache( + hass: HomeAssistant, mock_device: AsyncMock, freezer: FrozenDateTimeFactory +) -> None: + """Test that the device isn't re-opened for subsequent refreshes.""" + assert mock_device.get_network_info.call_count == 1 + assert mock_device.open.call_count == 1 + + freezer.tick(timedelta(seconds=60)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert mock_device.get_network_info.call_count == 2 + assert mock_device.open.call_count == 1