Improve exception handling in Nord Pool (#130386)

* Improve exception handling in Nord Pool

* Improve auth string

* Remove auth
pull/130327/head^2
G Johansson 2024-11-11 23:02:48 +01:00 committed by GitHub
parent d1c3e1caa9
commit 3eab72b2aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 31 additions and 78 deletions

View File

@ -4,7 +4,12 @@ from __future__ import annotations
from typing import Any
from pynordpool import Currency, NordPoolClient, NordPoolError
from pynordpool import (
Currency,
NordPoolClient,
NordPoolEmptyResponseError,
NordPoolError,
)
from pynordpool.const import AREAS
import voluptuous as vol
@ -53,17 +58,16 @@ async def test_api(hass: HomeAssistant, user_input: dict[str, Any]) -> dict[str,
"""Test fetch data from Nord Pool."""
client = NordPoolClient(async_get_clientsession(hass))
try:
data = await client.async_get_delivery_period(
await client.async_get_delivery_period(
dt_util.now(),
Currency(user_input[CONF_CURRENCY]),
user_input[CONF_AREAS],
)
except NordPoolEmptyResponseError:
return {"base": "no_data"}
except NordPoolError:
return {"base": "cannot_connect"}
if not data.raw:
return {"base": "no_data"}
return {}

View File

@ -9,8 +9,8 @@ from typing import TYPE_CHECKING
from pynordpool import (
Currency,
DeliveryPeriodData,
NordPoolAuthenticationError,
NordPoolClient,
NordPoolEmptyResponseError,
NordPoolError,
NordPoolResponseError,
)
@ -19,7 +19,7 @@ from homeassistant.const import CONF_CURRENCY
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from homeassistant.util import dt as dt_util
from .const import CONF_AREAS, DOMAIN, LOGGER
@ -75,8 +75,8 @@ class NordPoolDataUpdateCoordinator(DataUpdateCoordinator[DeliveryPeriodData]):
Currency(self.config_entry.data[CONF_CURRENCY]),
self.config_entry.data[CONF_AREAS],
)
except NordPoolAuthenticationError as error:
LOGGER.error("Authentication error: %s", error)
except NordPoolEmptyResponseError as error:
LOGGER.debug("Empty response error: %s", error)
self.async_set_update_error(error)
return
except NordPoolResponseError as error:
@ -88,8 +88,4 @@ class NordPoolDataUpdateCoordinator(DataUpdateCoordinator[DeliveryPeriodData]):
self.async_set_update_error(error)
return
if not data.raw:
self.async_set_update_error(UpdateFailed("No data"))
return
self.async_set_updated_data(data)

View File

@ -2,13 +2,12 @@
from __future__ import annotations
from dataclasses import replace
from unittest.mock import patch
from pynordpool import (
DeliveryPeriodData,
NordPoolAuthenticationError,
NordPoolConnectionError,
NordPoolEmptyResponseError,
NordPoolError,
NordPoolResponseError,
)
@ -71,7 +70,7 @@ async def test_single_config_entry(
("error_message", "p_error"),
[
(NordPoolConnectionError, "cannot_connect"),
(NordPoolAuthenticationError, "cannot_connect"),
(NordPoolEmptyResponseError, "no_data"),
(NordPoolError, "cannot_connect"),
(NordPoolResponseError, "cannot_connect"),
],
@ -116,44 +115,6 @@ async def test_cannot_connect(
assert result["data"] == {"areas": ["SE3", "SE4"], "currency": "SEK"}
@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00")
async def test_empty_data(hass: HomeAssistant, get_data: DeliveryPeriodData) -> None:
"""Test empty data error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == config_entries.SOURCE_USER
invalid_data = replace(get_data, raw={})
with patch(
"homeassistant.components.nordpool.coordinator.NordPoolClient.async_get_delivery_period",
return_value=invalid_data,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=ENTRY_CONFIG,
)
assert result["errors"] == {"base": "no_data"}
with patch(
"homeassistant.components.nordpool.coordinator.NordPoolClient.async_get_delivery_period",
return_value=get_data,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=ENTRY_CONFIG,
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "Nord Pool"
assert result["data"] == {"areas": ["SE3", "SE4"], "currency": "SEK"}
@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00")
async def test_reconfigure(
hass: HomeAssistant,
@ -193,7 +154,7 @@ async def test_reconfigure(
("error_message", "p_error"),
[
(NordPoolConnectionError, "cannot_connect"),
(NordPoolAuthenticationError, "cannot_connect"),
(NordPoolEmptyResponseError, "no_data"),
(NordPoolError, "cannot_connect"),
(NordPoolResponseError, "cannot_connect"),
],

View File

@ -9,6 +9,7 @@ from freezegun.api import FrozenDateTimeFactory
from pynordpool import (
DeliveryPeriodData,
NordPoolAuthenticationError,
NordPoolEmptyResponseError,
NordPoolError,
NordPoolResponseError,
)
@ -18,14 +19,13 @@ from homeassistant.components.nordpool.const import DOMAIN
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
from homeassistant.util import dt as dt_util
from . import ENTRY_CONFIG
from tests.common import MockConfigEntry, async_fire_time_changed
@pytest.mark.freeze_time("2024-11-05T12:00:00+00:00")
@pytest.mark.freeze_time("2024-11-05T10:00:00+00:00")
async def test_coordinator(
hass: HomeAssistant,
get_data: DeliveryPeriodData,
@ -51,7 +51,7 @@ async def test_coordinator(
await hass.async_block_till_done()
mock_data.assert_called_once()
state = hass.states.get("sensor.nord_pool_se3_current_price")
assert state.state == "0.94949"
assert state.state == "0.92737"
mock_data.reset_mock()
mock_data.side_effect = NordPoolError("error")
@ -74,6 +74,17 @@ async def test_coordinator(
assert "Authentication error" in caplog.text
mock_data.reset_mock()
assert "Empty response" not in caplog.text
mock_data.side_effect = NordPoolEmptyResponseError("Empty response")
freezer.tick(timedelta(hours=1))
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
mock_data.assert_called_once()
state = hass.states.get("sensor.nord_pool_se3_current_price")
assert state.state == STATE_UNAVAILABLE
assert "Empty response" in caplog.text
mock_data.reset_mock()
assert "Response error" not in caplog.text
mock_data.side_effect = NordPoolResponseError("Response error")
freezer.tick(timedelta(hours=1))
@ -85,25 +96,6 @@ async def test_coordinator(
assert "Response error" in caplog.text
mock_data.reset_mock()
mock_data.return_value = DeliveryPeriodData(
raw={},
requested_date="2024-11-05",
updated_at=dt_util.utcnow(),
entries=[],
block_prices=[],
currency="SEK",
exchange_rate=1,
area_average={},
)
mock_data.side_effect = None
freezer.tick(timedelta(hours=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
mock_data.assert_called_once()
state = hass.states.get("sensor.nord_pool_se3_current_price")
assert state.state == STATE_UNAVAILABLE
mock_data.reset_mock()
mock_data.return_value = get_data
mock_data.side_effect = None
freezer.tick(timedelta(hours=1))
@ -111,4 +103,4 @@ async def test_coordinator(
await hass.async_block_till_done()
mock_data.assert_called_once()
state = hass.states.get("sensor.nord_pool_se3_current_price")
assert state.state == "1.81983"
assert state.state == "1.81645"