Indicate database migration in /api/core/state response (#122445)

* Indicate database migration in /api/core/state response

* Change API response according to review comment

* Adjust API response

* Update test

* Add test
This commit is contained in:
Erik Montnemery 2024-07-23 14:13:08 +02:00 committed by GitHub
parent 73ea62edd4
commit 92acfc1464
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 73 additions and 16 deletions

View File

@ -45,7 +45,7 @@ from homeassistant.exceptions import (
TemplateError, TemplateError,
Unauthorized, Unauthorized,
) )
from homeassistant.helpers import config_validation as cv, template from homeassistant.helpers import config_validation as cv, recorder, template
from homeassistant.helpers.json import json_dumps, json_fragment from homeassistant.helpers.json import json_dumps, json_fragment
from homeassistant.helpers.service import async_get_all_descriptions from homeassistant.helpers.service import async_get_all_descriptions
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
@ -118,8 +118,11 @@ class APICoreStateView(HomeAssistantView):
Home Assistant core is running. Its primary use case is for supervisor Home Assistant core is running. Its primary use case is for supervisor
to check if Home Assistant is running. to check if Home Assistant is running.
""" """
hass = request.app[KEY_HASS] hass: HomeAssistant = request.app[KEY_HASS]
return self.json({"state": hass.state.value}) migration = recorder.async_migration_in_progress(hass)
live = recorder.async_migration_is_live(hass)
recorder_state = {"migration_in_progress": migration, "migration_is_live": live}
return self.json({"state": hass.state.value, "recorder_state": recorder_state})
class APIEventStream(HomeAssistantView): class APIEventStream(HomeAssistantView):

View File

@ -20,16 +20,24 @@ class RecorderData:
db_connected: asyncio.Future[bool] = field(default_factory=asyncio.Future) db_connected: asyncio.Future[bool] = field(default_factory=asyncio.Future)
@callback
def async_migration_in_progress(hass: HomeAssistant) -> bool: def async_migration_in_progress(hass: HomeAssistant) -> bool:
"""Check to see if a recorder migration is in progress.""" """Check to see if a recorder migration is in progress."""
if "recorder" not in hass.config.components:
return False
# pylint: disable-next=import-outside-toplevel # pylint: disable-next=import-outside-toplevel
from homeassistant.components import recorder from homeassistant.components import recorder
return recorder.util.async_migration_in_progress(hass) return recorder.util.async_migration_in_progress(hass)
@callback
def async_migration_is_live(hass: HomeAssistant) -> bool:
"""Check to see if a recorder migration is live."""
# pylint: disable-next=import-outside-toplevel
from homeassistant.components import recorder
return recorder.util.async_migration_is_live(hass)
@callback @callback
def async_initialize_recorder(hass: HomeAssistant) -> None: def async_initialize_recorder(hass: HomeAssistant) -> None:
"""Initialize recorder data.""" """Initialize recorder data."""

View File

@ -770,4 +770,43 @@ async def test_api_core_state(hass: HomeAssistant, mock_api_client: TestClient)
resp = await mock_api_client.get("/api/core/state") resp = await mock_api_client.get("/api/core/state")
assert resp.status == HTTPStatus.OK assert resp.status == HTTPStatus.OK
json = await resp.json() json = await resp.json()
assert json["state"] == "RUNNING" assert json == {
"state": "RUNNING",
"recorder_state": {"migration_in_progress": False, "migration_is_live": False},
}
@pytest.mark.parametrize(
("migration_in_progress", "migration_is_live"),
[
(False, False),
(False, True),
(True, False),
(True, True),
],
)
async def test_api_core_state_recorder_migrating(
hass: HomeAssistant,
mock_api_client: TestClient,
migration_in_progress: bool,
migration_is_live: bool,
) -> None:
"""Test getting core status."""
with (
patch(
"homeassistant.helpers.recorder.async_migration_in_progress",
return_value=migration_in_progress,
),
patch(
"homeassistant.helpers.recorder.async_migration_is_live",
return_value=migration_is_live,
),
):
resp = await mock_api_client.get("/api/core/state")
assert resp.status == HTTPStatus.OK
json = await resp.json()
expected_recorder_state = {
"migration_in_progress": migration_in_progress,
"migration_is_live": migration_is_live,
}
assert json == {"state": "RUNNING", "recorder_state": expected_recorder_state}

View File

@ -18,18 +18,25 @@ async def test_async_migration_in_progress(
): ):
assert recorder.async_migration_in_progress(hass) is False assert recorder.async_migration_in_progress(hass) is False
# The recorder is not loaded
with patch(
"homeassistant.components.recorder.util.async_migration_in_progress",
return_value=True,
):
assert recorder.async_migration_in_progress(hass) is False
await async_setup_recorder_instance(hass)
# The recorder is now loaded
with patch( with patch(
"homeassistant.components.recorder.util.async_migration_in_progress", "homeassistant.components.recorder.util.async_migration_in_progress",
return_value=True, return_value=True,
): ):
assert recorder.async_migration_in_progress(hass) is True assert recorder.async_migration_in_progress(hass) is True
async def test_async_migration_is_live(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant
) -> None:
"""Test async_migration_in_progress wraps the recorder."""
with patch(
"homeassistant.components.recorder.util.async_migration_is_live",
return_value=False,
):
assert recorder.async_migration_is_live(hass) is False
with patch(
"homeassistant.components.recorder.util.async_migration_is_live",
return_value=True,
):
assert recorder.async_migration_is_live(hass) is True