1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-24 12:59:34 +00:00

Use parent_id to find cause of logbook events with new contexts (#44416)

* Use parent_id to find cause of events with new contexts

When looking up the causing event for logbook display, use the `parent_id`
of the current context if the current context just points back to the
current event.

This now shows in the logbook the cause of an event in the case that a
component has created a new context from an existing context and tied
them together via the `Context.parent_id`.

* Fix exception when parent event not available

* Use async_Log_entry to avoid jump into executor
This commit is contained in:
Michael Chisholm
2021-01-08 17:27:03 +11:00
committed by GitHub
parent 3b184ad11c
commit e35e460e69
2 changed files with 228 additions and 36 deletions

View File

@@ -282,6 +282,7 @@ def create_state_changed_event_from_old_new(
"time_fired"
"context_id"
"context_user_id"
"context_parent_id"
"state"
"entity_id"
"domain"
@@ -300,6 +301,7 @@ def create_state_changed_event_from_old_new(
row.domain = entity_id and ha.split_entity_id(entity_id)[0]
row.context_id = None
row.context_user_id = None
row.context_parent_id = None
row.old_state_id = old_state and 1
row.state_id = new_state and 1
return logbook.LazyEventPartialState(row)
@@ -946,6 +948,187 @@ async def test_logbook_entity_context_id(hass, hass_client):
assert json_dict[7]["context_user_id"] == "9400facee45711eaa9308bfd3d19e474"
async def test_logbook_entity_context_parent_id(hass, hass_client):
"""Test the logbook view links events via context parent_id."""
await hass.async_add_executor_job(init_recorder_component, hass)
await async_setup_component(hass, "logbook", {})
await async_setup_component(hass, "automation", {})
await async_setup_component(hass, "script", {})
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
context = ha.Context(
id="ac5bd62de45711eaaeb351041eec8dd9",
user_id="b400facee45711eaa9308bfd3d19e474",
)
# An Automation triggering scripts with a new context
automation_entity_id_test = "automation.alarm"
hass.bus.async_fire(
EVENT_AUTOMATION_TRIGGERED,
{ATTR_NAME: "Mock automation", ATTR_ENTITY_ID: automation_entity_id_test},
context=context,
)
child_context = ha.Context(
id="2798bfedf8234b5e9f4009c91f48f30c",
parent_id="ac5bd62de45711eaaeb351041eec8dd9",
user_id="b400facee45711eaa9308bfd3d19e474",
)
hass.bus.async_fire(
EVENT_SCRIPT_STARTED,
{ATTR_NAME: "Mock script", ATTR_ENTITY_ID: "script.mock_script"},
context=child_context,
)
hass.states.async_set(
automation_entity_id_test,
STATE_ON,
{ATTR_FRIENDLY_NAME: "Alarm Automation"},
context=child_context,
)
entity_id_test = "alarm_control_panel.area_001"
hass.states.async_set(entity_id_test, STATE_OFF, context=child_context)
await hass.async_block_till_done()
hass.states.async_set(entity_id_test, STATE_ON, context=child_context)
await hass.async_block_till_done()
entity_id_second = "alarm_control_panel.area_002"
hass.states.async_set(entity_id_second, STATE_OFF, context=child_context)
await hass.async_block_till_done()
hass.states.async_set(entity_id_second, STATE_ON, context=child_context)
await hass.async_block_till_done()
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
await hass.async_block_till_done()
logbook.async_log_entry(
hass,
"mock_name",
"mock_message",
"alarm_control_panel",
"alarm_control_panel.area_003",
child_context,
)
await hass.async_block_till_done()
logbook.async_log_entry(
hass,
"mock_name",
"mock_message",
"homeassistant",
None,
child_context,
)
await hass.async_block_till_done()
# A state change via service call with the script as the parent
light_turn_off_service_context = ha.Context(
id="9c5bd62de45711eaaeb351041eec8dd9",
parent_id="2798bfedf8234b5e9f4009c91f48f30c",
user_id="9400facee45711eaa9308bfd3d19e474",
)
hass.states.async_set("light.switch", STATE_ON)
await hass.async_block_till_done()
hass.bus.async_fire(
EVENT_CALL_SERVICE,
{
ATTR_DOMAIN: "light",
ATTR_SERVICE: "turn_off",
ATTR_ENTITY_ID: "light.switch",
},
context=light_turn_off_service_context,
)
await hass.async_block_till_done()
hass.states.async_set(
"light.switch", STATE_OFF, context=light_turn_off_service_context
)
await hass.async_block_till_done()
# An event with a parent event, but the parent event isn't available
missing_parent_context = ha.Context(
id="fc40b9a0d1f246f98c34b33c76228ee6",
parent_id="c8ce515fe58e442f8664246c65ed964f",
user_id="485cacf93ef84d25a99ced3126b921d2",
)
logbook.async_log_entry(
hass,
"mock_name",
"mock_message",
"alarm_control_panel",
"alarm_control_panel.area_009",
missing_parent_context,
)
await hass.async_block_till_done()
await hass.async_add_executor_job(trigger_db_commit, hass)
await hass.async_block_till_done()
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
client = await hass_client()
# Today time 00:00:00
start = dt_util.utcnow().date()
start_date = datetime(start.year, start.month, start.day)
# Test today entries with filter by end_time
end_time = start + timedelta(hours=24)
response = await client.get(
f"/api/logbook/{start_date.isoformat()}?end_time={end_time}"
)
assert response.status == 200
json_dict = await response.json()
assert json_dict[0]["entity_id"] == "automation.alarm"
assert "context_entity_id" not in json_dict[0]
assert json_dict[0]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
# New context, so this looks to be triggered by the Alarm Automation
assert json_dict[1]["entity_id"] == "script.mock_script"
assert json_dict[1]["context_event_type"] == "automation_triggered"
assert json_dict[1]["context_entity_id"] == "automation.alarm"
assert json_dict[1]["context_entity_id_name"] == "Alarm Automation"
assert json_dict[1]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
assert json_dict[2]["entity_id"] == entity_id_test
assert json_dict[2]["context_event_type"] == "script_started"
assert json_dict[2]["context_entity_id"] == "script.mock_script"
assert json_dict[2]["context_entity_id_name"] == "mock script"
assert json_dict[2]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
assert json_dict[3]["entity_id"] == entity_id_second
assert json_dict[3]["context_event_type"] == "script_started"
assert json_dict[3]["context_entity_id"] == "script.mock_script"
assert json_dict[3]["context_entity_id_name"] == "mock script"
assert json_dict[3]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
assert json_dict[4]["domain"] == "homeassistant"
assert json_dict[5]["entity_id"] == "alarm_control_panel.area_003"
assert json_dict[5]["context_event_type"] == "script_started"
assert json_dict[5]["context_entity_id"] == "script.mock_script"
assert json_dict[5]["domain"] == "alarm_control_panel"
assert json_dict[5]["context_entity_id_name"] == "mock script"
assert json_dict[5]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
assert json_dict[6]["domain"] == "homeassistant"
assert json_dict[6]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
assert json_dict[7]["entity_id"] == "light.switch"
assert json_dict[7]["context_event_type"] == "call_service"
assert json_dict[7]["context_domain"] == "light"
assert json_dict[7]["context_service"] == "turn_off"
assert json_dict[7]["context_user_id"] == "9400facee45711eaa9308bfd3d19e474"
assert json_dict[8]["entity_id"] == "alarm_control_panel.area_009"
assert json_dict[8]["domain"] == "alarm_control_panel"
assert "context_event_type" not in json_dict[8]
assert "context_entity_id" not in json_dict[8]
assert "context_entity_id_name" not in json_dict[8]
assert json_dict[8]["context_user_id"] == "485cacf93ef84d25a99ced3126b921d2"
async def test_logbook_context_from_template(hass, hass_client):
"""Test the logbook view with end_time and entity with automations and scripts."""
await hass.async_add_executor_job(init_recorder_component, hass)