Add diagnostics to remote calendar (#141111)

* Add diagnostics

* add diagnostics

* address review

* ruff

* ruff

* use raw ics data

* mypy

* mypy

* naming

* redact ics

* ruff

* simpify

* reduce data

* ruff
This commit is contained in:
Thomas55555 2025-03-22 20:27:48 +01:00 committed by GitHub
parent 6d91bdb02e
commit 61e30d0e91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 85 additions and 5 deletions

View File

@ -26,6 +26,7 @@ class RemoteCalendarDataUpdateCoordinator(DataUpdateCoordinator[Calendar]):
"""Class to manage fetching calendar data."""
config_entry: RemoteCalendarConfigEntry
ics: str
def __init__(
self,
@ -40,7 +41,6 @@ class RemoteCalendarDataUpdateCoordinator(DataUpdateCoordinator[Calendar]):
update_interval=SCAN_INTERVAL,
always_update=True,
)
self._etag = None
self._client = get_async_client(hass)
self._url = config_entry.data[CONF_URL]
@ -59,8 +59,9 @@ class RemoteCalendarDataUpdateCoordinator(DataUpdateCoordinator[Calendar]):
# calendar_from_ics will dynamically load packages
# the first time it is called, so we need to do it
# in a separate thread to avoid blocking the event loop
self.ics = res.text
return await self.hass.async_add_executor_job(
IcsCalendarStream.calendar_from_ics, res.text
IcsCalendarStream.calendar_from_ics, self.ics
)
except CalendarParseError as err:
raise UpdateFailed(

View File

@ -0,0 +1,25 @@
"""Provides diagnostics for the remote calendar."""
import datetime
from typing import Any
from ical.diagnostics import redact_ics
from homeassistant.core import HomeAssistant
from homeassistant.util import dt as dt_util
from . import RemoteCalendarConfigEntry
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, entry: RemoteCalendarConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
coordinator = entry.runtime_data
payload: dict[str, Any] = {
"now": dt_util.now().isoformat(),
"timezone": str(dt_util.get_default_time_zone()),
"system_timezone": str(datetime.datetime.now().astimezone().tzinfo),
}
payload["ics"] = "\n".join(redact_ics(coordinator.ics))
return payload

View File

@ -53,9 +53,7 @@ rules:
devices:
status: exempt
comment: No devices. One URL is always assigned to one calendar.
diagnostics:
status: todo
comment: Diagnostics not implemented, yet.
diagnostics: done
discovery-update-info:
status: todo
comment: No discovery protocol available.

View File

@ -0,0 +1,17 @@
# serializer version: 1
# name: test_entry_diagnostics
dict({
'ics': '''
BEGIN:VCALENDAR
BEGIN:VEVENT
SUMMARY:***
DTSTART:19970714T170000Z
DTEND:19970715T040000Z
END:VEVENT
END:VCALENDAR
''',
'now': '2023-06-04T18:00:00-06:00',
'system_timezone': 'tzlocal()',
'timezone': 'America/Regina',
})
# ---

View File

@ -0,0 +1,39 @@
"""Test the remote calendar diagnostics."""
import datetime
from httpx import Response
import pytest
import respx
from syrupy.assertion import SnapshotAssertion
from homeassistant.core import HomeAssistant
from . import setup_integration
from .conftest import CALENDER_URL
from tests.common import MockConfigEntry
from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator
@respx.mock
@pytest.mark.freeze_time(datetime.datetime(2023, 6, 5))
async def test_entry_diagnostics(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
snapshot: SnapshotAssertion,
config_entry: MockConfigEntry,
ics_content: str,
) -> None:
"""Test config entry diagnostics."""
respx.get(CALENDER_URL).mock(
return_value=Response(
status_code=200,
text=ics_content,
)
)
await setup_integration(hass, config_entry)
await hass.async_block_till_done()
result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
assert result == snapshot