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

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

299 lines
8.5 KiB
Python
Raw Normal View History

2023-09-23 12:04:44 -07:00
"""Test fixtures for fitbit."""
from collections.abc import Awaitable, Callable, Generator
import datetime
from http import HTTPStatus
import time
from typing import Any
from unittest.mock import patch
import pytest
from requests_mock.mocker import Mocker
from homeassistant.components.application_credentials import (
ClientCredential,
async_import_client_credential,
)
from homeassistant.components.fitbit.const import (
CONF_CLIENT_ID,
CONF_CLIENT_SECRET,
DOMAIN,
OAUTH_SCOPES,
)
from homeassistant.const import Platform
2023-09-23 12:04:44 -07:00
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry
2023-09-23 12:04:44 -07:00
CLIENT_ID = "1234"
CLIENT_SECRET = "5678"
PROFILE_USER_ID = "fitbit-api-user-id-1"
FAKE_ACCESS_TOKEN = "some-access-token"
2023-09-23 12:04:44 -07:00
FAKE_REFRESH_TOKEN = "some-refresh-token"
FAKE_AUTH_IMPL = "conftest-imported-cred"
FULL_NAME = "First Last"
DISPLAY_NAME = "First L."
PROFILE_DATA = {
"fullName": FULL_NAME,
"displayName": DISPLAY_NAME,
"displayNameSetting": "name",
"firstName": "First",
"lastName": "Last",
}
2023-09-23 12:04:44 -07:00
PROFILE_API_URL = "https://api.fitbit.com/1/user/-/profile.json"
DEVICES_API_URL = "https://api.fitbit.com/1/user/-/devices.json"
TIMESERIES_API_URL_FORMAT = (
"https://api.fitbit.com/1/user/-/{resource}/date/today/7d.json"
)
# These constants differ from values in the config entry or fitbit.conf
SERVER_ACCESS_TOKEN = {
"refresh_token": "server-refresh-token",
"access_token": "server-access-token",
"type": "Bearer",
"expires_in": 60,
"scope": " ".join(OAUTH_SCOPES),
}
2023-09-23 12:04:44 -07:00
@pytest.fixture(name="token_expiration_time")
def mcok_token_expiration_time() -> float:
"""Fixture for expiration time of the config entry auth token."""
return time.time() + 86400
@pytest.fixture(name="scopes")
def mock_scopes() -> list[str]:
"""Fixture for expiration time of the config entry auth token."""
return OAUTH_SCOPES
@pytest.fixture(name="token_entry")
def mock_token_entry(token_expiration_time: float, scopes: list[str]) -> dict[str, Any]:
"""Fixture for OAuth 'token' data for a ConfigEntry."""
return {
"access_token": FAKE_ACCESS_TOKEN,
"refresh_token": FAKE_REFRESH_TOKEN,
"scope": " ".join(scopes),
"token_type": "Bearer",
"expires_at": token_expiration_time,
}
@pytest.fixture(name="config_entry")
def mock_config_entry(token_entry: dict[str, Any]) -> MockConfigEntry:
"""Fixture for a config entry."""
return MockConfigEntry(
domain=DOMAIN,
data={
"auth_implementation": FAKE_AUTH_IMPL,
"token": token_entry,
},
unique_id=PROFILE_USER_ID,
)
@pytest.fixture
async def setup_credentials(hass: HomeAssistant) -> None:
"""Fixture to setup credentials."""
assert await async_setup_component(hass, "application_credentials", {})
await async_import_client_credential(
hass,
DOMAIN,
ClientCredential(CLIENT_ID, CLIENT_SECRET),
FAKE_AUTH_IMPL,
)
2023-09-23 12:04:44 -07:00
@pytest.fixture(name="fitbit_config_yaml")
def mock_fitbit_config_yaml(token_expiration_time: float) -> dict[str, Any] | None:
2023-09-23 12:04:44 -07:00
"""Fixture for the yaml fitbit.conf file contents."""
return {
CONF_CLIENT_ID: CLIENT_ID,
CONF_CLIENT_SECRET: CLIENT_SECRET,
"access_token": FAKE_ACCESS_TOKEN,
2023-09-23 12:04:44 -07:00
"refresh_token": FAKE_REFRESH_TOKEN,
"last_saved_at": token_expiration_time,
}
@pytest.fixture(name="fitbit_config_setup")
2023-09-23 12:04:44 -07:00
def mock_fitbit_config_setup(
fitbit_config_yaml: dict[str, Any] | None,
2023-09-23 12:04:44 -07:00
) -> Generator[None, None, None]:
"""Fixture to mock out fitbit.conf file data loading and persistence."""
has_config = fitbit_config_yaml is not None
2023-09-23 12:04:44 -07:00
with (
patch(
"homeassistant.components.fitbit.sensor.os.path.isfile",
return_value=has_config,
2023-09-23 12:04:44 -07:00
),
patch(
"homeassistant.components.fitbit.sensor.load_json_object",
return_value=fitbit_config_yaml,
2024-03-26 00:02:16 +01:00
),
2023-09-23 12:04:44 -07:00
):
yield
@pytest.fixture(name="monitored_resources")
def mock_monitored_resources() -> list[str] | None:
"""Fixture for the fitbit yaml config monitored_resources field."""
return None
@pytest.fixture(name="configured_unit_system")
def mock_configured_unit_syststem() -> str | None:
"""Fixture for the fitbit yaml config monitored_resources field."""
return None
2023-09-23 12:04:44 -07:00
@pytest.fixture(name="sensor_platform_config")
def mock_sensor_platform_config(
monitored_resources: list[str] | None,
configured_unit_system: str | None,
2023-09-23 12:04:44 -07:00
) -> dict[str, Any]:
"""Fixture for the fitbit sensor platform configuration data in configuration.yaml."""
config = {}
if monitored_resources is not None:
config["monitored_resources"] = monitored_resources
if configured_unit_system is not None:
config["unit_system"] = configured_unit_system
2023-09-23 12:04:44 -07:00
return config
@pytest.fixture(name="sensor_platform_setup")
async def mock_sensor_platform_setup(
hass: HomeAssistant,
sensor_platform_config: dict[str, Any],
) -> Callable[[], Awaitable[bool]]:
"""Fixture to set up the integration."""
async def run() -> bool:
result = await async_setup_component(
hass,
"sensor",
{
"sensor": [
{
"platform": DOMAIN,
**sensor_platform_config,
}
]
},
)
await hass.async_block_till_done()
return result
return run
@pytest.fixture
def platforms() -> list[Platform]:
"""Fixture to specify platforms to test."""
return []
@pytest.fixture(name="integration_setup")
async def mock_integration_setup(
hass: HomeAssistant,
config_entry: MockConfigEntry,
platforms: list[str],
) -> Callable[[], Awaitable[bool]]:
"""Fixture to set up the integration."""
config_entry.add_to_hass(hass)
async def run() -> bool:
with patch(f"homeassistant.components.{DOMAIN}.PLATFORMS", platforms):
result = await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
2023-09-23 12:04:44 -07:00
return result
return run
@pytest.fixture(name="profile_id")
def mock_profile_id() -> str:
2023-09-23 12:04:44 -07:00
"""Fixture for the profile id returned from the API response."""
return PROFILE_USER_ID
@pytest.fixture(name="profile_locale")
def mock_profile_locale() -> str:
"""Fixture to set the API response for the user profile."""
return "en_US"
@pytest.fixture(name="profile_data")
def mock_profile_data() -> dict[str, Any]:
"""Fixture to return other profile data fields."""
return PROFILE_DATA
@pytest.fixture(name="profile_response")
def mock_profile_response(
profile_id: str, profile_locale: str, profile_data: dict[str, Any]
) -> dict[str, Any]:
"""Fixture to construct the fake profile API response."""
return {
"user": {
"encodedId": profile_id,
"locale": profile_locale,
**profile_data,
},
}
2023-09-23 12:04:44 -07:00
@pytest.fixture(name="profile", autouse=True)
def mock_profile(requests_mock: Mocker, profile_response: dict[str, Any]) -> None:
2023-09-23 12:04:44 -07:00
"""Fixture to setup fake requests made to Fitbit API during config flow."""
requests_mock.register_uri(
"GET",
PROFILE_API_URL,
status_code=HTTPStatus.OK,
json=profile_response,
2023-09-23 12:04:44 -07:00
)
@pytest.fixture(name="devices_response")
def mock_device_response() -> list[dict[str, Any]]:
2023-09-23 12:04:44 -07:00
"""Return the list of devices."""
return []
@pytest.fixture(autouse=True)
def mock_devices(requests_mock: Mocker, devices_response: dict[str, Any]) -> None:
2023-09-23 12:04:44 -07:00
"""Fixture to setup fake device responses."""
requests_mock.register_uri(
"GET",
DEVICES_API_URL,
status_code=HTTPStatus.OK,
json=devices_response,
)
def timeseries_response(resource: str, value: str) -> dict[str, Any]:
"""Create a timeseries response value."""
return {
resource: [{"dateTime": datetime.datetime.today().isoformat(), "value": value}]
}
@pytest.fixture(name="register_timeseries")
def mock_register_timeseries(
2023-09-23 12:04:44 -07:00
requests_mock: Mocker,
) -> Callable[[str, dict[str, Any]], None]:
"""Fixture to setup fake timeseries API responses."""
def register(resource: str, response: dict[str, Any]) -> None:
requests_mock.register_uri(
"GET",
TIMESERIES_API_URL_FORMAT.format(resource=resource),
status_code=HTTPStatus.OK,
json=response,
)
return register