Skip to content

Commit 8c59196

Browse files
authored
Provide log info for discovered flows in logger (home-assistant#157454)
1 parent 326f7f0 commit 8c59196

File tree

3 files changed

+129
-3
lines changed

3 files changed

+129
-3
lines changed

homeassistant/components/logger/helpers.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,16 @@ def async_save(self, delay: float = SAVE_DELAY) -> None:
181181
"""Save settings."""
182182
self._store.async_delay_save(self._async_data_to_save, delay)
183183

184+
@callback
185+
def async_get_integration_domains(self) -> set[str]:
186+
"""Get domains that have integration-level log settings."""
187+
stored_log_config = self._stored_config[STORAGE_LOG_KEY]
188+
return {
189+
domain
190+
for domain, setting in stored_log_config.items()
191+
if setting.type == LogSettingsType.INTEGRATION
192+
}
193+
184194
@callback
185195
def _async_get_logger_logs(self) -> dict[str, int]:
186196
"""Get the logger logs."""

homeassistant/components/logger/websocket_api.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from homeassistant.components import websocket_api
88
from homeassistant.components.websocket_api import ActiveConnection
9+
from homeassistant.config_entries import DISCOVERY_SOURCES
910
from homeassistant.core import HomeAssistant, callback
1011
from homeassistant.loader import IntegrationNotFound, async_get_integration
1112
from homeassistant.setup import async_get_loaded_integrations
@@ -34,6 +35,16 @@ def handle_integration_log_info(
3435
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
3536
) -> None:
3637
"""Handle integrations logger info."""
38+
integrations = set(async_get_loaded_integrations(hass))
39+
40+
# Add discovered config flows that are not yet loaded
41+
for flow in hass.config_entries.flow.async_progress():
42+
if flow["context"].get("source") in DISCOVERY_SOURCES:
43+
integrations.add(flow["handler"])
44+
45+
# Add integrations with custom log settings
46+
integrations.update(hass.data[DATA_LOGGER].settings.async_get_integration_domains())
47+
3748
connection.send_result(
3849
msg["id"],
3950
[
@@ -43,7 +54,7 @@ def handle_integration_log_info(
4354
f"homeassistant.components.{integration}"
4455
).getEffectiveLevel(),
4556
}
46-
for integration in async_get_loaded_integrations(hass)
57+
for integration in integrations
4758
],
4859
)
4960

tests/components/logger/test_websocket_api.py

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@
33
import logging
44
from unittest.mock import patch
55

6-
from homeassistant import loader
6+
from homeassistant import config_entries, loader
77
from homeassistant.components.logger.helpers import DATA_LOGGER
88
from homeassistant.components.websocket_api import TYPE_RESULT
99
from homeassistant.core import HomeAssistant
1010
from homeassistant.setup import async_setup_component
1111

12-
from tests.common import MockUser
12+
from tests.common import (
13+
MockModule,
14+
MockUser,
15+
mock_config_flow,
16+
mock_integration,
17+
mock_platform,
18+
)
1319
from tests.typing import WebSocketGenerator
1420

1521

@@ -33,6 +39,105 @@ async def test_integration_log_info(
3339
assert {"domain": "http", "level": logging.DEBUG} in msg["result"]
3440

3541

42+
async def test_integration_log_info_discovered_flows(
43+
hass: HomeAssistant, hass_ws_client: WebSocketGenerator, hass_admin_user: MockUser
44+
) -> None:
45+
"""Test that log info includes discovered flows."""
46+
assert await async_setup_component(hass, "logger", {})
47+
48+
# Set up a discovery flow (zeroconf)
49+
mock_integration(hass, MockModule("discovered_integration"))
50+
mock_platform(hass, "discovered_integration.config_flow", None)
51+
52+
class DiscoveryFlow(config_entries.ConfigFlow, domain="discovered_integration"):
53+
"""Test discovery flow."""
54+
55+
VERSION = 1
56+
57+
async def async_step_zeroconf(self, discovery_info=None):
58+
"""Test zeroconf step."""
59+
return self.async_show_form(step_id="zeroconf")
60+
61+
# Set up a user flow (non-discovery)
62+
mock_integration(hass, MockModule("user_flow_integration"))
63+
mock_platform(hass, "user_flow_integration.config_flow", None)
64+
65+
class UserFlow(config_entries.ConfigFlow, domain="user_flow_integration"):
66+
"""Test user flow."""
67+
68+
VERSION = 1
69+
70+
async def async_step_user(self, user_input=None):
71+
"""Test user step."""
72+
return self.async_show_form(step_id="user")
73+
74+
with (
75+
mock_config_flow("discovered_integration", DiscoveryFlow),
76+
mock_config_flow("user_flow_integration", UserFlow),
77+
):
78+
# Start both flows
79+
await hass.config_entries.flow.async_init(
80+
"discovered_integration",
81+
context={"source": config_entries.SOURCE_ZEROCONF},
82+
)
83+
await hass.config_entries.flow.async_init(
84+
"user_flow_integration",
85+
context={"source": config_entries.SOURCE_USER},
86+
)
87+
88+
# Verify both flows are in progress
89+
flows = hass.config_entries.flow.async_progress()
90+
assert len(flows) == 2
91+
92+
websocket_client = await hass_ws_client()
93+
await websocket_client.send_json({"id": 7, "type": "logger/log_info"})
94+
95+
msg = await websocket_client.receive_json()
96+
assert msg["id"] == 7
97+
assert msg["type"] == TYPE_RESULT
98+
assert msg["success"]
99+
100+
domains = [item["domain"] for item in msg["result"]]
101+
# Discovery flow should be included
102+
assert "discovered_integration" in domains
103+
# User flow should NOT be included (not a discovery source)
104+
assert "user_flow_integration" not in domains
105+
106+
107+
async def test_integration_log_info_with_settings(
108+
hass: HomeAssistant, hass_ws_client: WebSocketGenerator, hass_admin_user: MockUser
109+
) -> None:
110+
"""Test that log info includes integrations with custom log settings."""
111+
assert await async_setup_component(hass, "logger", {})
112+
113+
# Set up a mock integration that is not loaded
114+
mock_integration(hass, MockModule("unloaded_integration"))
115+
116+
# Set a log level for this unloaded integration
117+
websocket_client = await hass_ws_client()
118+
await websocket_client.send_json(
119+
{
120+
"id": 1,
121+
"type": "logger/integration_log_level",
122+
"integration": "unloaded_integration",
123+
"level": "DEBUG",
124+
"persistence": "none",
125+
}
126+
)
127+
msg = await websocket_client.receive_json()
128+
assert msg["success"]
129+
130+
# Now check log_info includes the unloaded integration with settings
131+
await websocket_client.send_json({"id": 2, "type": "logger/log_info"})
132+
133+
msg = await websocket_client.receive_json()
134+
assert msg["id"] == 2
135+
assert msg["success"]
136+
137+
domains = [item["domain"] for item in msg["result"]]
138+
assert "unloaded_integration" in domains
139+
140+
36141
async def test_integration_log_level_logger_not_loaded(
37142
hass: HomeAssistant, hass_ws_client: WebSocketGenerator, hass_admin_user: MockUser
38143
) -> None:

0 commit comments

Comments
 (0)