Files
core/tests/components/growatt_server/test_init.py

177 lines
5.6 KiB
Python

"""Tests for the Growatt Server integration."""
from datetime import timedelta
import json
from unittest.mock import patch
from freezegun.api import FrozenDateTimeFactory
import growattServer
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.growatt_server.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from . import setup_integration
from tests.common import MockConfigEntry, async_fire_time_changed
@pytest.mark.usefixtures("init_integration")
async def test_load_unload_config_entry(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test loading and unloading the integration."""
assert mock_config_entry.state is ConfigEntryState.LOADED
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
@pytest.mark.usefixtures("init_integration")
async def test_device_info(
snapshot: SnapshotAssertion,
device_registry: dr.DeviceRegistry,
) -> None:
"""Test device registry integration."""
device_entry = device_registry.async_get_device(identifiers={(DOMAIN, "MIN123456")})
assert device_entry is not None
assert device_entry == snapshot
@pytest.mark.parametrize(
("exception", "expected_state"),
[
(growattServer.GrowattV1ApiError("API Error"), ConfigEntryState.SETUP_ERROR),
(
json.decoder.JSONDecodeError("Invalid JSON", "", 0),
ConfigEntryState.SETUP_ERROR,
),
],
)
async def test_setup_error_on_api_failure(
hass: HomeAssistant,
mock_growatt_v1_api,
mock_config_entry: MockConfigEntry,
exception: Exception,
expected_state: ConfigEntryState,
) -> None:
"""Test setup error on API failures during device list."""
mock_growatt_v1_api.device_list.side_effect = exception
await setup_integration(hass, mock_config_entry)
assert mock_config_entry.state is expected_state
@pytest.mark.usefixtures("init_integration")
async def test_coordinator_update_failed(
hass: HomeAssistant,
mock_growatt_v1_api,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test coordinator handles update failures gracefully."""
# Integration should be loaded
assert mock_config_entry.state is ConfigEntryState.LOADED
# Cause coordinator update to fail
mock_growatt_v1_api.min_detail.side_effect = growattServer.GrowattV1ApiError(
"Connection timeout"
)
# Trigger coordinator refresh
freezer.tick(timedelta(minutes=5))
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
# Integration should remain loaded despite coordinator error
assert mock_config_entry.state is ConfigEntryState.LOADED
async def test_classic_api_setup(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
mock_growatt_classic_api,
mock_config_entry_classic: MockConfigEntry,
device_registry: dr.DeviceRegistry,
) -> None:
"""Test integration setup with Classic API (password auth)."""
# Classic API doesn't support MIN devices - use TLX device instead
mock_growatt_classic_api.device_list.return_value = [
{"deviceSn": "TLX123456", "deviceType": "tlx"}
]
await setup_integration(hass, mock_config_entry_classic)
assert mock_config_entry_classic.state is ConfigEntryState.LOADED
# Verify Classic API login was called
mock_growatt_classic_api.login.assert_called()
# Verify device was created
device_entry = device_registry.async_get_device(identifiers={(DOMAIN, "TLX123456")})
assert device_entry is not None
assert device_entry == snapshot
@pytest.mark.usefixtures("init_integration")
async def test_unload_removes_listeners(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test that unloading removes all listeners."""
# Get initial listener count
initial_listeners = len(hass.bus.async_listeners())
# Unload the integration
await hass.config_entries.async_unload(mock_config_entry.entry_id)
await hass.async_block_till_done()
# Verify listeners were removed (should be same or less)
final_listeners = len(hass.bus.async_listeners())
assert final_listeners <= initial_listeners
async def test_multiple_devices_discovered(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
mock_growatt_v1_api,
mock_config_entry: MockConfigEntry,
device_registry: dr.DeviceRegistry,
) -> None:
"""Test handling multiple devices from device_list."""
# Reset and add multiple devices
mock_config_entry_new = MockConfigEntry(
domain=DOMAIN,
data=mock_config_entry.data,
unique_id="plant_456",
)
mock_growatt_v1_api.device_list.return_value = {
"devices": [
{"device_sn": "MIN123456", "type": 7},
{"device_sn": "MIN789012", "type": 7},
]
}
with patch(
"homeassistant.components.growatt_server.coordinator.SCAN_INTERVAL",
timedelta(minutes=5),
):
await setup_integration(hass, mock_config_entry_new)
# Verify both devices were created
device1 = device_registry.async_get_device(identifiers={(DOMAIN, "MIN123456")})
device2 = device_registry.async_get_device(identifiers={(DOMAIN, "MIN789012")})
assert device1 is not None
assert device1 == snapshot(name="device_min123456")
assert device2 is not None
assert device2 == snapshot(name="device_min789012")