mirror of
https://github.com/home-assistant/core.git
synced 2026-09-26 01:11:51 -04:00
Fix Glances to use dedicated httpx client with longer timeout and surface API error messages (#169689)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: Joostlek <joostlek@outlook.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
Joostlek
parent
10aebaf423
commit
99ab58e58a
@@ -26,8 +26,9 @@ from homeassistant.exceptions import (
|
||||
ConfigEntryNotReady,
|
||||
HomeAssistantError,
|
||||
)
|
||||
from homeassistant.helpers.httpx_client import get_async_client
|
||||
from homeassistant.helpers.httpx_client import create_async_httpx_client
|
||||
|
||||
from .const import DEFAULT_TIMEOUT
|
||||
from .coordinator import GlancesConfigEntry, GlancesDataUpdateCoordinator
|
||||
|
||||
PLATFORMS = [Platform.SENSOR]
|
||||
@@ -65,7 +66,11 @@ async def async_unload_entry(hass: HomeAssistant, entry: GlancesConfigEntry) ->
|
||||
|
||||
async def get_api(hass: HomeAssistant, entry_data: dict[str, Any]) -> Glances:
|
||||
"""Return the api from glances_api."""
|
||||
httpx_client = get_async_client(hass, verify_ssl=entry_data[CONF_VERIFY_SSL])
|
||||
# The shared httpx client cannot be used because its 5-second timeout
|
||||
# is too short for slow Glances hosts.
|
||||
httpx_client = create_async_httpx_client(
|
||||
hass, verify_ssl=entry_data[CONF_VERIFY_SSL], timeout=DEFAULT_TIMEOUT
|
||||
)
|
||||
for version in (4, 3):
|
||||
api = Glances(
|
||||
host=entry_data[CONF_HOST],
|
||||
|
||||
@@ -9,5 +9,6 @@ CONF_VERSION = "version"
|
||||
DEFAULT_HOST = "localhost"
|
||||
DEFAULT_PORT = 61208
|
||||
DEFAULT_SCAN_INTERVAL = timedelta(seconds=60)
|
||||
DEFAULT_TIMEOUT = 30
|
||||
|
||||
CPU_ICON = f"mdi:cpu-{64 if sys.maxsize > 2**32 else 32}-bit"
|
||||
|
||||
@@ -47,7 +47,7 @@ class GlancesDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
except exceptions.GlancesApiAuthorizationError as err:
|
||||
raise ConfigEntryAuthFailed from err
|
||||
except exceptions.GlancesApiError as err:
|
||||
raise UpdateFailed from err
|
||||
raise UpdateFailed(str(err)) from err
|
||||
# Update computed values
|
||||
uptime: datetime | None = None
|
||||
up_duration: timedelta | None = None
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"""Tests for Glances integration."""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
from glances_api.exceptions import (
|
||||
GlancesApiAuthorizationError,
|
||||
GlancesApiConnectionError,
|
||||
@@ -9,13 +10,18 @@ from glances_api.exceptions import (
|
||||
)
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.glances.const import DOMAIN
|
||||
from homeassistant.components.glances.const import (
|
||||
DEFAULT_SCAN_INTERVAL,
|
||||
DEFAULT_TIMEOUT,
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import STATE_UNAVAILABLE
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import MOCK_USER_INPUT
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
|
||||
|
||||
async def test_successful_config_entry(hass: HomeAssistant) -> None:
|
||||
@@ -53,6 +59,49 @@ async def test_setup_error(
|
||||
assert entry.state is entry_state
|
||||
|
||||
|
||||
async def test_entity_unavailable_on_update_error(
|
||||
hass: HomeAssistant,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
mock_api: MagicMock,
|
||||
) -> None:
|
||||
"""Test that entities become unavailable when a data update fails."""
|
||||
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_INPUT)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
assert hass.states.get("sensor.0_0_0_0_ssl_disk_used").state != STATE_UNAVAILABLE
|
||||
|
||||
mock_api.return_value.get_ha_sensor_data.side_effect = GlancesApiConnectionError(
|
||||
"Connection to http://localhost:61209/api/4/all failed"
|
||||
)
|
||||
freezer.tick(DEFAULT_SCAN_INTERVAL)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get("sensor.0_0_0_0_ssl_disk_used").state == STATE_UNAVAILABLE
|
||||
|
||||
|
||||
async def test_dedicated_httpx_client_uses_timeout(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""The integration's dedicated httpx client uses DEFAULT_TIMEOUT."""
|
||||
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_INPUT)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.glances.create_async_httpx_client"
|
||||
) as mock_create:
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
|
||||
kwargs = mock_create.call_args.kwargs
|
||||
assert kwargs["timeout"] == DEFAULT_TIMEOUT
|
||||
assert kwargs["verify_ssl"] == MOCK_USER_INPUT["verify_ssl"]
|
||||
|
||||
|
||||
async def test_unload_entry(hass: HomeAssistant) -> None:
|
||||
"""Test removing Glances."""
|
||||
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_INPUT)
|
||||
|
||||
Reference in New Issue
Block a user