Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refresh token before setting up weheat #135264

Merged
merged 3 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion homeassistant/components/weheat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

from __future__ import annotations

from http import HTTPStatus

import aiohttp
from weheat.abstractions.discovery import HeatPumpDiscovery
from weheat.exceptions import UnauthorizedException

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ACCESS_TOKEN, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers.config_entry_oauth2_flow import (
OAuth2Session,
async_get_config_entry_implementation,
Expand All @@ -28,6 +31,18 @@ async def async_setup_entry(hass: HomeAssistant, entry: WeheatConfigEntry) -> bo

session = OAuth2Session(hass, entry, implementation)

try:
await session.async_ensure_token_valid()
except aiohttp.ClientResponseError as ex:
LOGGER.warning("API error: %s (%s)", ex.status, ex.message)
if ex.status in (
HTTPStatus.BAD_REQUEST,
HTTPStatus.UNAUTHORIZED,
HTTPStatus.FORBIDDEN,
):
raise ConfigEntryAuthFailed("Token not valid, trigger renewal") from ex
raise ConfigEntryNotReady from ex

token = session.token[CONF_ACCESS_TOKEN]
entry.runtime_data = []

Expand Down
85 changes: 85 additions & 0 deletions tests/components/weheat/test_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"""Tests for the weheat initialization."""

from http import HTTPStatus
from unittest.mock import AsyncMock, Mock, patch

import pytest
from weheat.abstractions.discovery import HeatPumpDiscovery

from homeassistant.components.weheat import UnauthorizedException
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant

from . import setup_integration

from tests.common import MockConfigEntry
from tests.test_util.aiohttp import ClientResponseError


@pytest.mark.usefixtures("setup_credentials")
async def test_setup(
hass: HomeAssistant,
mock_weheat_discover: AsyncMock,
mock_weheat_heat_pump: AsyncMock,
mock_heat_pump_info: HeatPumpDiscovery.HeatPumpInfo,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test the Weheat setup."""
mock_weheat_discover.return_value = [mock_heat_pump_info]

await setup_integration(hass, mock_config_entry)

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("setup_credentials")
@pytest.mark.parametrize(
("setup_exception", "expected_setup_state"),
[
(HTTPStatus.BAD_REQUEST, ConfigEntryState.SETUP_ERROR),
(HTTPStatus.UNAUTHORIZED, ConfigEntryState.SETUP_ERROR),
(HTTPStatus.FORBIDDEN, ConfigEntryState.SETUP_ERROR),
(HTTPStatus.GATEWAY_TIMEOUT, ConfigEntryState.SETUP_RETRY),
],
)
async def test_setup_fail(
hass: HomeAssistant,
mock_weheat_discover: AsyncMock,
mock_weheat_heat_pump: AsyncMock,
mock_heat_pump_info: HeatPumpDiscovery.HeatPumpInfo,
mock_config_entry: MockConfigEntry,
setup_exception: Exception,
expected_setup_state: ConfigEntryState,
) -> None:
"""Test the Weheat setup with invalid token setup."""
with (
patch(
"homeassistant.components.weheat.OAuth2Session.async_ensure_token_valid",
side_effect=ClientResponseError(
Mock(real_url="http://example.com"), None, status=setup_exception
),
),
):
await setup_integration(hass, mock_config_entry)

assert mock_config_entry.state is expected_setup_state


@pytest.mark.usefixtures("setup_credentials")
async def test_setup_fail_discover(
hass: HomeAssistant,
mock_weheat_discover: AsyncMock,
mock_weheat_heat_pump: AsyncMock,
mock_heat_pump_info: HeatPumpDiscovery.HeatPumpInfo,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test the Weheat setup with and error from the heat pump discovery."""
mock_weheat_discover.side_effect = UnauthorizedException()

await setup_integration(hass, mock_config_entry)

assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR