mirror of
https://github.com/home-assistant/core.git
synced 2025-07-26 06:37:52 +00:00
Improve exception handling in Nord Pool (#130386)
* Improve exception handling in Nord Pool * Improve auth string * Remove auth
This commit is contained in:
parent
d1c3e1caa9
commit
3eab72b2aa
@ -4,7 +4,12 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from pynordpool import Currency, NordPoolClient, NordPoolError
|
from pynordpool import (
|
||||||
|
Currency,
|
||||||
|
NordPoolClient,
|
||||||
|
NordPoolEmptyResponseError,
|
||||||
|
NordPoolError,
|
||||||
|
)
|
||||||
from pynordpool.const import AREAS
|
from pynordpool.const import AREAS
|
||||||
import voluptuous as vol
|
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."""
|
"""Test fetch data from Nord Pool."""
|
||||||
client = NordPoolClient(async_get_clientsession(hass))
|
client = NordPoolClient(async_get_clientsession(hass))
|
||||||
try:
|
try:
|
||||||
data = await client.async_get_delivery_period(
|
await client.async_get_delivery_period(
|
||||||
dt_util.now(),
|
dt_util.now(),
|
||||||
Currency(user_input[CONF_CURRENCY]),
|
Currency(user_input[CONF_CURRENCY]),
|
||||||
user_input[CONF_AREAS],
|
user_input[CONF_AREAS],
|
||||||
)
|
)
|
||||||
|
except NordPoolEmptyResponseError:
|
||||||
|
return {"base": "no_data"}
|
||||||
except NordPoolError:
|
except NordPoolError:
|
||||||
return {"base": "cannot_connect"}
|
return {"base": "cannot_connect"}
|
||||||
|
|
||||||
if not data.raw:
|
|
||||||
return {"base": "no_data"}
|
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,8 +9,8 @@ from typing import TYPE_CHECKING
|
|||||||
from pynordpool import (
|
from pynordpool import (
|
||||||
Currency,
|
Currency,
|
||||||
DeliveryPeriodData,
|
DeliveryPeriodData,
|
||||||
NordPoolAuthenticationError,
|
|
||||||
NordPoolClient,
|
NordPoolClient,
|
||||||
|
NordPoolEmptyResponseError,
|
||||||
NordPoolError,
|
NordPoolError,
|
||||||
NordPoolResponseError,
|
NordPoolResponseError,
|
||||||
)
|
)
|
||||||
@ -19,7 +19,7 @@ from homeassistant.const import CONF_CURRENCY
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
from homeassistant.helpers.event import async_track_point_in_utc_time
|
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 homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from .const import CONF_AREAS, DOMAIN, LOGGER
|
from .const import CONF_AREAS, DOMAIN, LOGGER
|
||||||
@ -75,8 +75,8 @@ class NordPoolDataUpdateCoordinator(DataUpdateCoordinator[DeliveryPeriodData]):
|
|||||||
Currency(self.config_entry.data[CONF_CURRENCY]),
|
Currency(self.config_entry.data[CONF_CURRENCY]),
|
||||||
self.config_entry.data[CONF_AREAS],
|
self.config_entry.data[CONF_AREAS],
|
||||||
)
|
)
|
||||||
except NordPoolAuthenticationError as error:
|
except NordPoolEmptyResponseError as error:
|
||||||
LOGGER.error("Authentication error: %s", error)
|
LOGGER.debug("Empty response error: %s", error)
|
||||||
self.async_set_update_error(error)
|
self.async_set_update_error(error)
|
||||||
return
|
return
|
||||||
except NordPoolResponseError as error:
|
except NordPoolResponseError as error:
|
||||||
@ -88,8 +88,4 @@ class NordPoolDataUpdateCoordinator(DataUpdateCoordinator[DeliveryPeriodData]):
|
|||||||
self.async_set_update_error(error)
|
self.async_set_update_error(error)
|
||||||
return
|
return
|
||||||
|
|
||||||
if not data.raw:
|
|
||||||
self.async_set_update_error(UpdateFailed("No data"))
|
|
||||||
return
|
|
||||||
|
|
||||||
self.async_set_updated_data(data)
|
self.async_set_updated_data(data)
|
||||||
|
@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import replace
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from pynordpool import (
|
from pynordpool import (
|
||||||
DeliveryPeriodData,
|
DeliveryPeriodData,
|
||||||
NordPoolAuthenticationError,
|
|
||||||
NordPoolConnectionError,
|
NordPoolConnectionError,
|
||||||
|
NordPoolEmptyResponseError,
|
||||||
NordPoolError,
|
NordPoolError,
|
||||||
NordPoolResponseError,
|
NordPoolResponseError,
|
||||||
)
|
)
|
||||||
@ -71,7 +70,7 @@ async def test_single_config_entry(
|
|||||||
("error_message", "p_error"),
|
("error_message", "p_error"),
|
||||||
[
|
[
|
||||||
(NordPoolConnectionError, "cannot_connect"),
|
(NordPoolConnectionError, "cannot_connect"),
|
||||||
(NordPoolAuthenticationError, "cannot_connect"),
|
(NordPoolEmptyResponseError, "no_data"),
|
||||||
(NordPoolError, "cannot_connect"),
|
(NordPoolError, "cannot_connect"),
|
||||||
(NordPoolResponseError, "cannot_connect"),
|
(NordPoolResponseError, "cannot_connect"),
|
||||||
],
|
],
|
||||||
@ -116,44 +115,6 @@ async def test_cannot_connect(
|
|||||||
assert result["data"] == {"areas": ["SE3", "SE4"], "currency": "SEK"}
|
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")
|
@pytest.mark.freeze_time("2024-11-05T18:00:00+00:00")
|
||||||
async def test_reconfigure(
|
async def test_reconfigure(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -193,7 +154,7 @@ async def test_reconfigure(
|
|||||||
("error_message", "p_error"),
|
("error_message", "p_error"),
|
||||||
[
|
[
|
||||||
(NordPoolConnectionError, "cannot_connect"),
|
(NordPoolConnectionError, "cannot_connect"),
|
||||||
(NordPoolAuthenticationError, "cannot_connect"),
|
(NordPoolEmptyResponseError, "no_data"),
|
||||||
(NordPoolError, "cannot_connect"),
|
(NordPoolError, "cannot_connect"),
|
||||||
(NordPoolResponseError, "cannot_connect"),
|
(NordPoolResponseError, "cannot_connect"),
|
||||||
],
|
],
|
||||||
|
@ -9,6 +9,7 @@ from freezegun.api import FrozenDateTimeFactory
|
|||||||
from pynordpool import (
|
from pynordpool import (
|
||||||
DeliveryPeriodData,
|
DeliveryPeriodData,
|
||||||
NordPoolAuthenticationError,
|
NordPoolAuthenticationError,
|
||||||
|
NordPoolEmptyResponseError,
|
||||||
NordPoolError,
|
NordPoolError,
|
||||||
NordPoolResponseError,
|
NordPoolResponseError,
|
||||||
)
|
)
|
||||||
@ -18,14 +19,13 @@ from homeassistant.components.nordpool.const import DOMAIN
|
|||||||
from homeassistant.config_entries import SOURCE_USER
|
from homeassistant.config_entries import SOURCE_USER
|
||||||
from homeassistant.const import STATE_UNAVAILABLE
|
from homeassistant.const import STATE_UNAVAILABLE
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.util import dt as dt_util
|
|
||||||
|
|
||||||
from . import ENTRY_CONFIG
|
from . import ENTRY_CONFIG
|
||||||
|
|
||||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
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(
|
async def test_coordinator(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
get_data: DeliveryPeriodData,
|
get_data: DeliveryPeriodData,
|
||||||
@ -51,7 +51,7 @@ async def test_coordinator(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
mock_data.assert_called_once()
|
mock_data.assert_called_once()
|
||||||
state = hass.states.get("sensor.nord_pool_se3_current_price")
|
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.reset_mock()
|
||||||
|
|
||||||
mock_data.side_effect = NordPoolError("error")
|
mock_data.side_effect = NordPoolError("error")
|
||||||
@ -74,6 +74,17 @@ async def test_coordinator(
|
|||||||
assert "Authentication error" in caplog.text
|
assert "Authentication error" in caplog.text
|
||||||
mock_data.reset_mock()
|
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
|
assert "Response error" not in caplog.text
|
||||||
mock_data.side_effect = NordPoolResponseError("Response error")
|
mock_data.side_effect = NordPoolResponseError("Response error")
|
||||||
freezer.tick(timedelta(hours=1))
|
freezer.tick(timedelta(hours=1))
|
||||||
@ -85,25 +96,6 @@ async def test_coordinator(
|
|||||||
assert "Response error" in caplog.text
|
assert "Response error" in caplog.text
|
||||||
mock_data.reset_mock()
|
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.return_value = get_data
|
||||||
mock_data.side_effect = None
|
mock_data.side_effect = None
|
||||||
freezer.tick(timedelta(hours=1))
|
freezer.tick(timedelta(hours=1))
|
||||||
@ -111,4 +103,4 @@ async def test_coordinator(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
mock_data.assert_called_once()
|
mock_data.assert_called_once()
|
||||||
state = hass.states.get("sensor.nord_pool_se3_current_price")
|
state = hass.states.get("sensor.nord_pool_se3_current_price")
|
||||||
assert state.state == "1.81983"
|
assert state.state == "1.81645"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user