core/tests/components/fronius/test_init.py

165 lines
5.8 KiB
Python

"""Test the Fronius integration."""
from datetime import timedelta
from unittest.mock import patch
from freezegun.api import FrozenDateTimeFactory
from pyfronius import FroniusError
from homeassistant.components.fronius.const import DOMAIN, SOLAR_NET_RESCAN_TIMER
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
from . import mock_responses, setup_fronius_integration
from tests.common import async_fire_time_changed
from tests.test_util.aiohttp import AiohttpClientMocker
from tests.typing import WebSocketGenerator
async def test_unload_config_entry(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test that configuration entry supports unloading."""
mock_responses(aioclient_mock)
await setup_fronius_integration(hass)
fronius_entries = hass.config_entries.async_entries(DOMAIN)
assert len(fronius_entries) == 1
test_entry = fronius_entries[0]
assert test_entry.state is ConfigEntryState.LOADED
assert await hass.config_entries.async_unload(test_entry.entry_id)
await hass.async_block_till_done()
assert test_entry.state is ConfigEntryState.NOT_LOADED
assert not hass.data.get(DOMAIN)
async def test_logger_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test setup when logger reports an error."""
# gen24 dataset will raise FroniusError when logger is called
mock_responses(aioclient_mock, fixture_set="gen24")
config_entry = await setup_fronius_integration(hass, is_logger=True)
assert config_entry.state is ConfigEntryState.SETUP_RETRY
async def test_inverter_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test setup when inverter_info reports an error."""
mock_responses(aioclient_mock)
with patch(
"pyfronius.Fronius.inverter_info",
side_effect=FroniusError,
):
config_entry = await setup_fronius_integration(hass)
assert config_entry.state is ConfigEntryState.SETUP_RETRY
async def test_inverter_night_rescan(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,
aioclient_mock: AiohttpClientMocker,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test dynamic adding of an inverter discovered automatically after a Home Assistant reboot during the night."""
mock_responses(aioclient_mock, fixture_set="igplus_v2", night=True)
config_entry = await setup_fronius_integration(hass, is_logger=True)
assert config_entry.state is ConfigEntryState.LOADED
# Only expect logger during the night
fronius_entries = hass.config_entries.async_entries(DOMAIN)
assert len(fronius_entries) == 1
# Switch to daytime
mock_responses(aioclient_mock, fixture_set="igplus_v2", night=False)
freezer.tick(timedelta(minutes=SOLAR_NET_RESCAN_TIMER))
async_fire_time_changed(hass)
await hass.async_block_till_done()
# We expect our inverter to be present now
inverter_1 = device_registry.async_get_device(identifiers={(DOMAIN, "203200")})
assert inverter_1.manufacturer == "Fronius"
# After another re-scan we still only expect this inverter
freezer.tick(timedelta(minutes=SOLAR_NET_RESCAN_TIMER))
async_fire_time_changed(hass)
await hass.async_block_till_done()
inverter_1 = device_registry.async_get_device(identifiers={(DOMAIN, "203200")})
assert inverter_1.manufacturer == "Fronius"
async def test_inverter_rescan_interruption(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,
aioclient_mock: AiohttpClientMocker,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test interruption of re-scan during runtime to process further."""
mock_responses(aioclient_mock, fixture_set="igplus_v2", night=True)
config_entry = await setup_fronius_integration(hass, is_logger=True)
assert config_entry.state is ConfigEntryState.LOADED
# Expect 1 devices during the night, logger
assert (
len(dr.async_entries_for_config_entry(device_registry, config_entry.entry_id))
== 1
)
with patch(
"pyfronius.Fronius.inverter_info",
side_effect=FroniusError,
):
freezer.tick(timedelta(minutes=SOLAR_NET_RESCAN_TIMER))
async_fire_time_changed(hass)
await hass.async_block_till_done()
# No increase of devices expected because of a FroniusError
assert (
len(
dr.async_entries_for_config_entry(
device_registry, config_entry.entry_id
)
)
== 1
)
# Next re-scan will pick up the new inverter. Expect 2 devices now.
mock_responses(aioclient_mock, fixture_set="igplus_v2", night=False)
freezer.tick(timedelta(minutes=SOLAR_NET_RESCAN_TIMER))
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert (
len(dr.async_entries_for_config_entry(device_registry, config_entry.entry_id))
== 2
)
async def test_device_remove_devices(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
device_registry: dr.DeviceRegistry,
entity_registry: er.EntityRegistry,
hass_ws_client: WebSocketGenerator,
) -> None:
"""Test we can remove a device."""
assert await async_setup_component(hass, "config", {})
mock_responses(aioclient_mock, fixture_set="gen24_storage")
config_entry = await setup_fronius_integration(
hass, is_logger=False, unique_id="12345678"
)
inverter_1 = device_registry.async_get_device(identifiers={(DOMAIN, "12345678")})
client = await hass_ws_client(hass)
response = await client.remove_device(inverter_1.id, config_entry.entry_id)
assert response["success"]
assert not device_registry.async_get_device(identifiers={(DOMAIN, "12345678")})