Files
core/tests/components/enphase_envoy/conftest.py
T

314 lines
11 KiB
Python

"""Define test fixtures for Enphase Envoy."""
from collections.abc import AsyncGenerator, Generator
from typing import Any
from unittest.mock import AsyncMock, Mock, patch
import multidict
from pyenphase import (
EnvoyACB,
EnvoyACBPower,
EnvoyBatteryAggregate,
EnvoyC6CC,
EnvoyCollar,
EnvoyData,
EnvoyEncharge,
EnvoyEnchargeAggregate,
EnvoyEnchargePower,
EnvoyEnpower,
EnvoyInverter,
EnvoySystemConsumption,
EnvoySystemProduction,
EnvoyTokenAuth,
)
from pyenphase.const import SupportedFeatures
from pyenphase.models.dry_contacts import EnvoyDryContactSettings, EnvoyDryContactStatus
from pyenphase.models.home import EnvoyInterfaceInformation
from pyenphase.models.meters import EnvoyMeterData
from pyenphase.models.tariff import EnvoyStorageSettings, EnvoyTariff
import pytest
from homeassistant.components.enphase_envoy import DOMAIN
from homeassistant.components.enphase_envoy.const import CONF_MANUAL_TOKEN
from homeassistant.const import (
CONF_HOST,
CONF_NAME,
CONF_PASSWORD,
CONF_TOKEN,
CONF_USERNAME,
)
from homeassistant.core import HomeAssistant
from . import envoy_token
from tests.common import MockConfigEntry, load_json_object_fixture
@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.enphase_envoy.async_setup_entry",
return_value=True,
) as mock_setup_entry:
yield mock_setup_entry
@pytest.fixture(name="config_entry")
def config_entry_fixture(
hass: HomeAssistant,
config: dict[str, Any],
request: pytest.FixtureRequest,
) -> MockConfigEntry:
"""Define a config entry fixture."""
token_mode = "none"
token_life = 365
if hasattr(request, "param"):
if isinstance(request.param, list):
token_mode = request.param[0]
if len(request.param) > 1:
token_life = request.param[1]
else:
token_mode = request.param
if token_mode == "none":
data = config
elif token_mode == "auto":
# config contains token from automatic retrieval
data = {
CONF_HOST: "1.1.1.1",
CONF_NAME: "Envoy 1234",
CONF_USERNAME: "test-username",
CONF_PASSWORD: "test-password",
CONF_TOKEN: envoy_token(token_life),
CONF_MANUAL_TOKEN: False,
}
elif token_mode == "manual":
# config contains token from manual entry
data = {
CONF_HOST: "1.1.1.1",
CONF_NAME: "Envoy 1234",
CONF_USERNAME: "",
CONF_PASSWORD: "",
CONF_TOKEN: envoy_token(token_life),
CONF_MANUAL_TOKEN: True,
}
return MockConfigEntry(
domain=DOMAIN,
entry_id="45a36e55aaddb2007c5f6602e0c38e72",
title="Envoy 1234",
unique_id="1234",
data=data,
)
@pytest.fixture(name="config")
def config_fixture() -> dict[str, str]:
"""Define a config entry data fixture."""
return {
CONF_HOST: "1.1.1.1",
CONF_NAME: "Envoy 1234",
CONF_USERNAME: "test-username",
CONF_PASSWORD: "test-password",
}
@pytest.fixture
async def mock_envoy(
request: pytest.FixtureRequest,
) -> AsyncGenerator[AsyncMock]:
"""Define a mocked Envoy fixture."""
new_token = envoy_token()
with (
patch(
"homeassistant.components.enphase_envoy.config_flow.Envoy",
autospec=True,
) as mock_client,
patch(
"homeassistant.components.enphase_envoy.Envoy",
new=mock_client,
),
patch(
"pyenphase.auth.EnvoyTokenAuth._obtain_token",
return_value=new_token,
),
):
mock_envoy = mock_client.return_value
# Add the fixtures specified
token = envoy_token(200)
mock_envoy.auth = EnvoyTokenAuth("127.0.0.1", token=token, envoy_serial="1234")
mock_envoy.serial_number = "1234"
mock = Mock()
mock.status = 200
aiohttp_text = AsyncMock()
aiohttp_text.return_value = "Testing request \nreplies."
mock.text = aiohttp_text
mock.headers = multidict.MultiDict([("Hello", "World")])
mock_envoy.request.return_value = mock
# determine fixture file name, default envoy if no request passed
fixture_name = "envoy"
if hasattr(request, "param"):
fixture_name = request.param
# Load envoy model from fixture
load_envoy_fixture(mock_envoy, fixture_name)
mock_envoy.update.return_value = mock_envoy.data
yield mock_envoy
def load_envoy_fixture(mock_envoy: AsyncMock, fixture_name: str) -> None:
"""Load envoy model from fixture."""
json_fixture: dict[str, Any] = load_json_object_fixture(
f"{fixture_name}.json", DOMAIN
)
mock_envoy.firmware = json_fixture["firmware"]
mock_envoy.part_number = json_fixture["part_number"]
mock_envoy.envoy_model = json_fixture["envoy_model"]
mock_envoy.supported_features = SupportedFeatures(
json_fixture["supported_features"]
)
mock_envoy.phase_mode = json_fixture["phase_mode"]
mock_envoy.phase_count = json_fixture["phase_count"]
mock_envoy.active_phase_count = json_fixture["active_phase_count"]
mock_envoy.ct_meter_count = json_fixture["ct_meter_count"]
mock_envoy.consumption_meter_type = json_fixture["consumption_meter_type"]
mock_envoy.production_meter_type = json_fixture["production_meter_type"]
mock_envoy.storage_meter_type = json_fixture["storage_meter_type"]
mock_envoy.data = EnvoyData()
_load_json_2_production_data(mock_envoy.data, json_fixture)
_load_json_2_meter_data(mock_envoy.data, json_fixture)
_load_json_2_inverter_data(mock_envoy.data, json_fixture)
_load_json_2_encharge_enpower_data(mock_envoy.data, json_fixture)
_load_json_2_acb_inventory_data(mock_envoy.data, json_fixture)
_load_json_2_raw_data(mock_envoy.data, json_fixture)
if item := json_fixture.get("interface_information"):
mock_envoy.interface_settings.return_value = EnvoyInterfaceInformation(**item)
else:
mock_envoy.interface_settings.return_value = None
def _load_json_2_production_data(
mocked_data: EnvoyData, json_fixture: dict[str, Any]
) -> None:
"""Fill envoy production data from fixture."""
if item := json_fixture["data"].get("system_consumption"):
mocked_data.system_consumption = EnvoySystemConsumption(**item)
if item := json_fixture["data"].get("system_net_consumption"):
mocked_data.system_net_consumption = EnvoySystemConsumption(**item)
if item := json_fixture["data"].get("system_production"):
mocked_data.system_production = EnvoySystemProduction(**item)
if item := json_fixture["data"].get("system_consumption_phases"):
mocked_data.system_consumption_phases = {}
for sub_item, item_data in item.items():
mocked_data.system_consumption_phases[sub_item] = EnvoySystemConsumption(
**item_data
)
if item := json_fixture["data"].get("system_net_consumption_phases"):
mocked_data.system_net_consumption_phases = {}
for sub_item, item_data in item.items():
mocked_data.system_net_consumption_phases[sub_item] = (
EnvoySystemConsumption(**item_data)
)
if item := json_fixture["data"].get("system_production_phases"):
mocked_data.system_production_phases = {}
for sub_item, item_data in item.items():
mocked_data.system_production_phases[sub_item] = EnvoySystemProduction(
**item_data
)
if item := json_fixture["data"].get("acb_power"):
mocked_data.acb_power = EnvoyACBPower(**item)
def _load_json_2_meter_data(
mocked_data: EnvoyData, json_fixture: dict[str, Any]
) -> None:
"""Fill envoy meter data from fixture."""
if meters := json_fixture["data"].get("ctmeters"):
mocked_data.ctmeters = {}
[
mocked_data.ctmeters.update({meter: EnvoyMeterData(**meter_data)})
for meter, meter_data in meters.items()
]
if meters := json_fixture["data"].get("ctmeters_phases"):
mocked_data.ctmeters_phases = {}
for meter, meter_data in meters.items():
meter_phase_data: dict[str, EnvoyMeterData] = {}
[
meter_phase_data.update({phase: EnvoyMeterData(**phase_data)})
for phase, phase_data in meter_data.items()
]
mocked_data.ctmeters_phases.update({meter: meter_phase_data})
def _load_json_2_inverter_data(
mocked_data: EnvoyData, json_fixture: dict[str, Any]
) -> None:
"""Fill envoy inverter data from fixture."""
if item := json_fixture["data"].get("inverters"):
mocked_data.inverters = {}
for sub_item, item_data in item.items():
mocked_data.inverters[sub_item] = EnvoyInverter(**item_data)
def _load_json_2_acb_inventory_data(
mocked_data: EnvoyData, json_fixture: dict[str, Any]
) -> None:
"""Fill envoy per-device ACB inventory data from fixture."""
if item := json_fixture["data"].get("acb_inventory"):
mocked_data.acb_inventory = {}
for sub_item, item_data in item.items():
mocked_data.acb_inventory[sub_item] = EnvoyACB(**item_data)
def _load_json_2_encharge_enpower_data(
mocked_data: EnvoyData, json_fixture: dict[str, Any]
) -> None:
"""Fill envoy encharge/enpower data from fixture."""
if item := json_fixture["data"].get("encharge_inventory"):
mocked_data.encharge_inventory = {}
for sub_item, item_data in item.items():
mocked_data.encharge_inventory[sub_item] = EnvoyEncharge(**item_data)
if item := json_fixture["data"].get("enpower"):
mocked_data.enpower = EnvoyEnpower(**item)
if item := json_fixture["data"].get("encharge_aggregate"):
mocked_data.encharge_aggregate = EnvoyEnchargeAggregate(**item)
if item := json_fixture["data"].get("encharge_power"):
mocked_data.encharge_power = {}
for sub_item, item_data in item.items():
mocked_data.encharge_power[sub_item] = EnvoyEnchargePower(**item_data)
if item := json_fixture["data"].get("tariff"):
mocked_data.tariff = EnvoyTariff(**item)
mocked_data.tariff.storage_settings = EnvoyStorageSettings(
**item["storage_settings"]
)
if item := json_fixture["data"].get("dry_contact_status"):
mocked_data.dry_contact_status = {}
for sub_item, item_data in item.items():
mocked_data.dry_contact_status[sub_item] = EnvoyDryContactStatus(
**item_data
)
if item := json_fixture["data"].get("dry_contact_settings"):
mocked_data.dry_contact_settings = {}
for sub_item, item_data in item.items():
mocked_data.dry_contact_settings[sub_item] = EnvoyDryContactSettings(
**item_data
)
if item := json_fixture["data"].get("battery_aggregate"):
mocked_data.battery_aggregate = EnvoyBatteryAggregate(**item)
if item := json_fixture["data"].get("collar"):
mocked_data.collar = EnvoyCollar(**item)
if item := json_fixture["data"].get("c6cc"):
mocked_data.c6cc = EnvoyC6CC(**item)
def _load_json_2_raw_data(mocked_data: EnvoyData, json_fixture: dict[str, Any]) -> None:
"""Fill envoy raw data from fixture."""
if item := json_fixture["data"].get("raw"):
mocked_data.raw = item