core/tests/components/diagnostics/test_init.py

368 lines
12 KiB
Python

"""Test the Diagnostics integration."""
from datetime import datetime
from http import HTTPStatus
from unittest.mock import AsyncMock, Mock, patch
from freezegun import freeze_time
import pytest
from homeassistant.components.websocket_api import TYPE_RESULT
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, issue_registry as ir
from homeassistant.helpers.system_info import async_get_system_info
from homeassistant.loader import async_get_integration
from homeassistant.setup import async_setup_component
from . import _get_diagnostics_for_config_entry, _get_diagnostics_for_device
from tests.common import MockConfigEntry, mock_platform
from tests.typing import ClientSessionGenerator, WebSocketGenerator
@pytest.fixture(autouse=True)
async def mock_diagnostics_integration(hass: HomeAssistant) -> None:
"""Mock a diagnostics integration."""
hass.config.components.add("fake_integration")
mock_platform(
hass,
"fake_integration.diagnostics",
Mock(
async_get_config_entry_diagnostics=AsyncMock(
return_value={
"config_entry": "info",
}
),
async_get_device_diagnostics=AsyncMock(
return_value={
"device": "info",
}
),
),
)
mock_platform(
hass,
"integration_without_diagnostics.diagnostics",
Mock(),
)
assert await async_setup_component(hass, "diagnostics", {})
async def test_websocket(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None:
"""Test websocket command."""
client = await hass_ws_client(hass)
await client.send_json({"id": 5, "type": "diagnostics/list"})
msg = await client.receive_json()
assert msg["id"] == 5
assert msg["type"] == TYPE_RESULT
assert msg["success"]
assert msg["result"] == [
{
"domain": "fake_integration",
"handlers": {"config_entry": True, "device": True},
}
]
await client.send_json(
{"id": 6, "type": "diagnostics/get", "domain": "fake_integration"}
)
msg = await client.receive_json()
assert msg["id"] == 6
assert msg["type"] == TYPE_RESULT
assert msg["success"]
assert msg["result"] == {
"domain": "fake_integration",
"handlers": {"config_entry": True, "device": True},
}
@pytest.mark.usefixtures("enable_custom_integrations")
@pytest.mark.parametrize(
"ignore_missing_translations",
[
[
"component.fake_integration.issues.test_issue.title",
"component.fake_integration.issues.test_issue.description",
]
],
)
async def test_download_diagnostics(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
device_registry: dr.DeviceRegistry,
issue_registry: ir.IssueRegistry,
) -> None:
"""Test download diagnostics."""
config_entry = MockConfigEntry(domain="fake_integration")
config_entry.add_to_hass(hass)
hass_sys_info = await async_get_system_info(hass)
hass_sys_info["run_as_root"] = hass_sys_info["user"] == "root"
del hass_sys_info["user"]
integration = await async_get_integration(hass, "fake_integration")
original_manifest = integration.manifest.copy()
original_manifest["codeowners"] = ["@test"]
with freeze_time(datetime(2025, 7, 9, 14, 00, 00)):
issue_registry.async_get_or_create(
domain="fake_integration",
issue_id="test_issue",
breaks_in_ha_version="2023.10.0",
severity=ir.IssueSeverity.WARNING,
is_fixable=False,
is_persistent=True,
translation_key="test_issue",
)
with patch.object(integration, "manifest", original_manifest):
response = await _get_diagnostics_for_config_entry(
hass, hass_client, config_entry
)
assert response == {
"home_assistant": hass_sys_info,
"setup_times": {},
"custom_components": {
"test": {
"documentation": "http://example.com",
"requirements": [],
"version": "1.2.3",
},
"test_blocked_version": {
"documentation": None,
"requirements": [],
"version": "1.0.0",
},
"test_embedded": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_integration_frame": {
"documentation": "http://example.com",
"requirements": [],
"version": "1.2.3",
},
"test_integration_platform": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_legacy_state_translations": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_legacy_state_translations_bad_data": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_package": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_package_loaded_executor": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_package_loaded_loop": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_package_raises_cancelled_error": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_package_raises_cancelled_error_config_entry": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_with_services": {
"documentation": None,
"requirements": [],
"version": "1.0",
},
},
"integration_manifest": {
"codeowners": ["test"],
"dependencies": [],
"domain": "fake_integration",
"is_built_in": True,
"overwrites_built_in": False,
"name": "fake_integration",
"requirements": [],
},
"data": {"config_entry": "info"},
"issues": [
{
"breaks_in_ha_version": "2023.10.0",
"created": "2025-07-09T14:00:00+00:00",
"data": None,
"dismissed_version": None,
"domain": "fake_integration",
"is_fixable": False,
"is_persistent": True,
"issue_domain": None,
"issue_id": "test_issue",
"learn_more_url": None,
"severity": "warning",
"translation_key": "test_issue",
"translation_placeholders": None,
},
],
}
device = device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id, identifiers={("test", "test")}
)
assert await _get_diagnostics_for_device(
hass, hass_client, config_entry, device
) == {
"home_assistant": hass_sys_info,
"custom_components": {
"test": {
"documentation": "http://example.com",
"requirements": [],
"version": "1.2.3",
},
"test_blocked_version": {
"documentation": None,
"requirements": [],
"version": "1.0.0",
},
"test_embedded": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_integration_frame": {
"documentation": "http://example.com",
"requirements": [],
"version": "1.2.3",
},
"test_integration_platform": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_legacy_state_translations": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_legacy_state_translations_bad_data": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_package": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_package_loaded_executor": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_package_loaded_loop": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_package_raises_cancelled_error": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_package_raises_cancelled_error_config_entry": {
"documentation": "http://test-package.io",
"requirements": [],
"version": "1.2.3",
},
"test_with_services": {
"documentation": None,
"requirements": [],
"version": "1.0",
},
},
"integration_manifest": {
"codeowners": [],
"dependencies": [],
"domain": "fake_integration",
"is_built_in": True,
"overwrites_built_in": False,
"name": "fake_integration",
"requirements": [],
},
"data": {"device": "info"},
"issues": [
{
"breaks_in_ha_version": "2023.10.0",
"created": "2025-07-09T14:00:00+00:00",
"data": None,
"dismissed_version": None,
"domain": "fake_integration",
"is_fixable": False,
"is_persistent": True,
"issue_domain": None,
"issue_id": "test_issue",
"learn_more_url": None,
"severity": "warning",
"translation_key": "test_issue",
"translation_placeholders": None,
},
],
"setup_times": {},
}
async def test_failure_scenarios(
hass: HomeAssistant, hass_client: ClientSessionGenerator
) -> None:
"""Test failure scenarios."""
client = await hass_client()
# test wrong d_type
response = await client.get("/api/diagnostics/wrong_type/fake_id")
assert response.status == HTTPStatus.BAD_REQUEST
# test wrong d_id
response = await client.get("/api/diagnostics/config_entry/fake_id")
assert response.status == HTTPStatus.NOT_FOUND
config_entry = MockConfigEntry(domain="integration_without_diagnostics")
config_entry.add_to_hass(hass)
# test valid d_type and d_id but no config entry diagnostics
response = await client.get(
f"/api/diagnostics/config_entry/{config_entry.entry_id}"
)
assert response.status == HTTPStatus.NOT_FOUND
config_entry = MockConfigEntry(domain="fake_integration")
config_entry.add_to_hass(hass)
# test invalid sub_type
response = await client.get(
f"/api/diagnostics/config_entry/{config_entry.entry_id}/wrong_type/id"
)
assert response.status == HTTPStatus.BAD_REQUEST
# test invalid sub_id
response = await client.get(
f"/api/diagnostics/config_entry/{config_entry.entry_id}/device/fake_id"
)
assert response.status == HTTPStatus.NOT_FOUND