diff --git a/.coveragerc b/.coveragerc index 0fff4590505..8687ba5a230 100644 --- a/.coveragerc +++ b/.coveragerc @@ -865,8 +865,6 @@ omit = homeassistant/components/pushbullet/sensor.py homeassistant/components/pushover/notify.py homeassistant/components/pushsafer/notify.py - homeassistant/components/pvoutput/__init__.py - homeassistant/components/pvoutput/coordinator.py homeassistant/components/pvoutput/sensor.py homeassistant/components/pyload/sensor.py homeassistant/components/qbittorrent/sensor.py diff --git a/tests/components/pvoutput/conftest.py b/tests/components/pvoutput/conftest.py index ad3e215570b..844bf157342 100644 --- a/tests/components/pvoutput/conftest.py +++ b/tests/components/pvoutput/conftest.py @@ -4,10 +4,12 @@ from __future__ import annotations from collections.abc import Generator from unittest.mock import AsyncMock, MagicMock, patch +from pvo import Status, System import pytest from homeassistant.components.pvoutput.const import CONF_SYSTEM_ID, DOMAIN from homeassistant.const import CONF_API_KEY +from homeassistant.core import HomeAssistant from tests.common import MockConfigEntry @@ -39,3 +41,45 @@ def mock_pvoutput_config_flow() -> Generator[None, MagicMock, None]: "homeassistant.components.pvoutput.config_flow.PVOutput", autospec=True ) as pvoutput_mock: yield pvoutput_mock.return_value + + +@pytest.fixture +def mock_pvoutput() -> Generator[None, MagicMock, None]: + """Return a mocked PVOutput client.""" + status = Status( + reported_date="20211229", + reported_time="22:37", + energy_consumption=1000, + energy_generation=500, + normalized_output=0.5, + power_consumption=2500, + power_generation=1500, + temperature=20.2, + voltage=220.5, + ) + + system = System( + inverter_brand="Super Inverters Inc.", + system_name="Frenck's Solar Farm", + ) + + with patch( + "homeassistant.components.pvoutput.coordinator.PVOutput", autospec=True + ) as pvoutput_mock: + pvoutput = pvoutput_mock.return_value + pvoutput.status.return_value = status + pvoutput.system.return_value = system + yield pvoutput + + +@pytest.fixture +async def init_integration( + hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_pvoutput: MagicMock +) -> MockConfigEntry: + """Set up the PVOutput integration for testing.""" + mock_config_entry.add_to_hass(hass) + + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + return mock_config_entry diff --git a/tests/components/pvoutput/test_init.py b/tests/components/pvoutput/test_init.py new file mode 100644 index 00000000000..faaff3d4214 --- /dev/null +++ b/tests/components/pvoutput/test_init.py @@ -0,0 +1,104 @@ +"""Tests for the PVOutput integration.""" +from unittest.mock import MagicMock + +from pvo import PVOutputAuthenticationError, PVOutputConnectionError +import pytest + +from homeassistant.components.pvoutput.const import CONF_SYSTEM_ID, DOMAIN +from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN +from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState +from homeassistant.const import CONF_API_KEY +from homeassistant.core import HomeAssistant +from homeassistant.setup import async_setup_component + +from tests.common import MockConfigEntry + + +async def test_load_unload_config_entry( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_pvoutput: MagicMock, +) -> None: + """Test the PVOutput configuration entry loading/unloading.""" + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert mock_config_entry.state is ConfigEntryState.LOADED + assert len(mock_pvoutput.status.mock_calls) == 1 + assert len(mock_pvoutput.system.mock_calls) == 1 + + await hass.config_entries.async_unload(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert not hass.data.get(DOMAIN) + assert mock_config_entry.state is ConfigEntryState.NOT_LOADED + + +async def test_config_entry_not_ready( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_pvoutput: MagicMock, +) -> None: + """Test the PVOutput configuration entry not ready.""" + mock_pvoutput.status.side_effect = PVOutputConnectionError + + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert len(mock_pvoutput.status.mock_calls) == 1 + assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY + + +async def test_config_entry_authentication_failed( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_pvoutput: MagicMock, +) -> None: + """Test trigger reauthentication flow.""" + mock_config_entry.add_to_hass(hass) + + mock_pvoutput.status.side_effect = PVOutputAuthenticationError + + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR + + flows = hass.config_entries.flow.async_progress() + assert len(flows) == 1 + + flow = flows[0] + assert flow.get("step_id") == "reauth_confirm" + assert flow.get("handler") == DOMAIN + + assert "context" in flow + assert flow["context"].get("source") == SOURCE_REAUTH + assert flow["context"].get("entry_id") == mock_config_entry.entry_id + + +async def test_import_config( + hass: HomeAssistant, + mock_pvoutput_config_flow: MagicMock, + mock_pvoutput: MagicMock, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test PVOutput being set up from config via import.""" + assert await async_setup_component( + hass, + SENSOR_DOMAIN, + { + SENSOR_DOMAIN: { + "platform": DOMAIN, + CONF_SYSTEM_ID: 12345, + CONF_API_KEY: "abcdefghijklmnopqrstuvwxyz", + } + }, + ) + await hass.async_block_till_done() + + assert len(hass.config_entries.async_entries(DOMAIN)) == 1 + assert len(mock_pvoutput.status.mock_calls) == 1 + assert len(mock_pvoutput.system.mock_calls) == 1 + assert "the PVOutput platform in YAML is deprecated" in caplog.text