Files
core/tests/components/tibber/conftest.py
2026-01-21 15:42:25 +01:00

239 lines
7.0 KiB
Python

"""Test helpers for Tibber."""
from collections.abc import AsyncGenerator
import time
from typing import Any
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
import tibber
from homeassistant.components.application_credentials import (
ClientCredential,
async_import_client_credential,
)
from homeassistant.components.recorder import Recorder
from homeassistant.components.tibber.const import AUTH_IMPLEMENTATION, DOMAIN
from homeassistant.const import CONF_ACCESS_TOKEN, Platform
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry
from tests.typing import RecorderInstanceContextManager
@pytest.fixture
async def mock_recorder_before_hass(
async_test_recorder: RecorderInstanceContextManager,
) -> None:
"""Set up recorder before hass fixture runs."""
def create_tibber_device(
device_id: str = "device-id",
external_id: str = "external-id",
name: str = "Test Device",
brand: str = "Tibber",
model: str = "Gen1",
home_id: str = "home-id",
state_of_charge: float | None = None,
connector_status: str | None = None,
charging_status: str | None = None,
device_status: str | None = None,
is_online: str | None = None,
sensor_values: dict[str, Any] | None = None,
) -> tibber.data_api.TibberDevice:
"""Create a fake Tibber Data API device.
Args:
device_id: Device ID.
external_id: External device ID.
name: Device name.
brand: Device brand.
model: Device model.
home_id: Home ID.
state_of_charge: Battery state of charge (for regular sensors).
connector_status: Connector status (for binary sensors).
charging_status: Charging status (for binary sensors).
device_status: Device on/off status (for binary sensors).
is_online: Device online status (for binary sensors).
sensor_values: Dictionary mapping sensor IDs to their values for additional sensors.
"""
capabilities = []
# Add regular sensor capabilities
if state_of_charge is not None:
capabilities.append(
{
"id": "storage.stateOfCharge",
"value": state_of_charge,
"description": "State of charge",
"unit": "%",
}
)
capabilities.append(
{
"id": "unknown.sensor.id",
"value": None,
"description": "Unknown",
"unit": "",
}
)
if connector_status is not None:
capabilities.append(
{
"id": "connector.status",
"value": connector_status,
"description": "Connector status",
"unit": "",
}
)
if charging_status is not None:
capabilities.append(
{
"id": "charging.status",
"value": charging_status,
"description": "Charging status",
"unit": "",
}
)
if device_status is not None:
capabilities.append(
{
"id": "onOff",
"value": device_status,
"description": "Device status",
"unit": "",
}
)
if is_online is not None:
capabilities.append(
{
"id": "isOnline",
"value": is_online,
"description": "Device online status",
"unit": "",
}
)
if sensor_values:
for sensor_id, value in sensor_values.items():
capabilities.append(
{
"id": sensor_id,
"value": value,
"description": sensor_id.replace(".", " ").title(),
"unit": "",
}
)
device_data = {
"id": device_id,
"externalId": external_id,
"info": {
"name": name,
"brand": brand,
"model": model,
},
"capabilities": capabilities,
}
return tibber.data_api.TibberDevice(device_data, home_id=home_id)
@pytest.fixture
def config_entry(hass: HomeAssistant) -> MockConfigEntry:
"""Tibber config entry."""
config_entry = MockConfigEntry(
domain=DOMAIN,
data={
CONF_ACCESS_TOKEN: "token",
AUTH_IMPLEMENTATION: DOMAIN,
"token": {
"access_token": "test-token",
"refresh_token": "refresh-token",
"token_type": "Bearer",
"expires_at": time.time() + 3600,
},
},
unique_id="tibber",
)
config_entry.add_to_hass(hass)
return config_entry
@pytest.fixture
def tibber_mock() -> AsyncGenerator[MagicMock]:
"""Patch the Tibber libraries used by the integration."""
unique_user_id = "unique_user_id"
title = "title"
with patch(
"tibber.Tibber",
autospec=True,
) as mock_tibber:
tibber_mock = mock_tibber.return_value
tibber_mock.update_info = AsyncMock(return_value=True)
tibber_mock.user_id = unique_user_id
tibber_mock.name = title
tibber_mock.send_notification = AsyncMock()
tibber_mock.rt_disconnect = AsyncMock()
tibber_mock.get_homes = MagicMock(return_value=[])
tibber_mock.set_access_token = MagicMock()
data_api_mock = MagicMock()
data_api_mock.get_all_devices = AsyncMock(return_value={})
data_api_mock.update_devices = AsyncMock(return_value={})
data_api_mock.get_userinfo = AsyncMock()
tibber_mock.data_api = data_api_mock
yield tibber_mock
@pytest.fixture
def data_api_client_mock(tibber_mock: MagicMock) -> MagicMock:
"""Return the patched Tibber Data API client mock."""
return tibber_mock.data_api
@pytest.fixture
async def mock_tibber_setup(
recorder_mock: Recorder,
config_entry: MockConfigEntry,
hass: HomeAssistant,
tibber_mock: MagicMock,
setup_credentials: None,
) -> MagicMock:
"""Mock tibber entry setup."""
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
return tibber_mock
@pytest.fixture
async def setup_credentials(hass: HomeAssistant) -> None:
"""Set up application credentials for the OAuth flow."""
assert await async_setup_component(hass, "application_credentials", {})
await async_import_client_credential(
hass,
DOMAIN,
ClientCredential("test-client-id", "test-client-secret"),
DOMAIN,
)
@pytest.fixture
def platforms() -> list[Platform]:
"""Fixture to specify platforms to test."""
return [Platform.BINARY_SENSOR, Platform.NOTIFY, Platform.SENSOR]
@pytest.fixture(autouse=True)
async def mock_patch_platforms(platforms: list[Platform]) -> AsyncGenerator[None]:
"""Fixture to set up platforms for tests."""
with patch(f"homeassistant.components.{DOMAIN}.PLATFORMS", platforms):
yield