Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for package errors #103902

Merged
merged 1 commit into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# adr007_1 should be a dict, this will cause a package error
adr_0007_1:
- host: blah.com

homeassistant:
packages:
pack_1:
# This is correct, but root config is wrong
adr_0007_1:
port: 8080
pack_2:
# Should not be a list
adr_0007_2:
- host: blah.com
pack_3:
# Host duplicated in pack_4
adr_0007_3:
host: blah.com
pack_4:
adr_0007_3:
host: blah.com
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# adr007_1 should be a dict, this will cause a package error
adr_0007_1:
- host: blah.com

homeassistant:
# Load packages
packages: !include_dir_named integrations
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# This is correct, but root config is wrong
adr_0007_1:
port: 8080
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Should not be a list
adr_0007_2:
- host: blah.com
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Host duplicated in adr_0007_3_2.yaml
adr_0007_3:
host: blah.com
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
adr_0007_3:
host: blah.com
42 changes: 28 additions & 14 deletions tests/snapshots/test_config.ambr
Original file line number Diff line number Diff line change
@@ -1,45 +1,59 @@
# serializer version: 1
# name: test_component_config_validation_error[basic]
list([
"Invalid config for [iot_domain.non_adr_0007]: expected str for dictionary value @ data['option1']. Got 123. (See <BASE_PATH>/fixtures/core/config/basic/configuration.yaml, line 6). ",
"Invalid config for [iot_domain]: required key not provided @ data['platform']. Got None. (See <BASE_PATH>/fixtures/core/config/basic/configuration.yaml, line 9). ",
"Invalid config for [iot_domain.non_adr_0007]: expected str for dictionary value @ data['option1']. Got 123. (See <BASE_PATH>/fixtures/core/config/component_validation/basic/configuration.yaml, line 6). ",
"Invalid config for [iot_domain]: required key not provided @ data['platform']. Got None. (See <BASE_PATH>/fixtures/core/config/component_validation/basic/configuration.yaml, line 9). ",
"Invalid config for [adr_0007_2]: required key not provided @ data['adr_0007_2']['host']. Got None. (See ?, line ?). ",
"Invalid config for [adr_0007_3]: expected int for dictionary value @ data['adr_0007_3']['port']. Got 'foo'. (See <BASE_PATH>/fixtures/core/config/basic/configuration.yaml, line 20). ",
"Invalid config for [adr_0007_3]: expected int for dictionary value @ data['adr_0007_3']['port']. Got 'foo'. (See <BASE_PATH>/fixtures/core/config/component_validation/basic/configuration.yaml, line 20). ",
])
# ---
# name: test_component_config_validation_error[basic_include]
list([
"Invalid config for [iot_domain.non_adr_0007]: expected str for dictionary value @ data['option1']. Got 123. (See <BASE_PATH>/fixtures/core/config/basic_include/integrations/iot_domain.yaml, line 5). ",
"Invalid config for [iot_domain]: required key not provided @ data['platform']. Got None. (See <BASE_PATH>/fixtures/core/config/basic_include/integrations/iot_domain.yaml, line 8). ",
"Invalid config for [iot_domain.non_adr_0007]: expected str for dictionary value @ data['option1']. Got 123. (See <BASE_PATH>/fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 5). ",
"Invalid config for [iot_domain]: required key not provided @ data['platform']. Got None. (See <BASE_PATH>/fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 8). ",
"Invalid config for [adr_0007_2]: required key not provided @ data['adr_0007_2']['host']. Got None. (See ?, line ?). ",
"Invalid config for [adr_0007_3]: expected int for dictionary value @ data['adr_0007_3']['port']. Got 'foo'. (See <BASE_PATH>/fixtures/core/config/basic_include/configuration.yaml, line 4). ",
"Invalid config for [adr_0007_3]: expected int for dictionary value @ data['adr_0007_3']['port']. Got 'foo'. (See <BASE_PATH>/fixtures/core/config/component_validation/basic_include/configuration.yaml, line 4). ",
])
# ---
# name: test_component_config_validation_error[include_dir_list]
list([
"Invalid config for [iot_domain.non_adr_0007]: expected str for dictionary value @ data['option1']. Got 123. (See <BASE_PATH>/fixtures/core/config/include_dir_list/iot_domain/iot_domain_2.yaml, line 2). ",
"Invalid config for [iot_domain]: required key not provided @ data['platform']. Got None. (See <BASE_PATH>/fixtures/core/config/include_dir_list/iot_domain/iot_domain_3.yaml, line 2). ",
"Invalid config for [iot_domain.non_adr_0007]: expected str for dictionary value @ data['option1']. Got 123. (See <BASE_PATH>/fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_2.yaml, line 2). ",
"Invalid config for [iot_domain]: required key not provided @ data['platform']. Got None. (See <BASE_PATH>/fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_3.yaml, line 2). ",
])
# ---
# name: test_component_config_validation_error[include_dir_merge_list]
list([
"Invalid config for [iot_domain.non_adr_0007]: expected str for dictionary value @ data['option1']. Got 123. (See <BASE_PATH>/fixtures/core/config/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 2). ",
"Invalid config for [iot_domain]: required key not provided @ data['platform']. Got None. (See <BASE_PATH>/fixtures/core/config/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 5). ",
"Invalid config for [iot_domain.non_adr_0007]: expected str for dictionary value @ data['option1']. Got 123. (See <BASE_PATH>/fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 2). ",
"Invalid config for [iot_domain]: required key not provided @ data['platform']. Got None. (See <BASE_PATH>/fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 5). ",
])
# ---
# name: test_component_config_validation_error[packages]
list([
"Invalid config for [iot_domain.non_adr_0007]: expected str for dictionary value @ data['option1']. Got 123. (See <BASE_PATH>/fixtures/core/config/packages/configuration.yaml, line 11). ",
"Invalid config for [iot_domain]: required key not provided @ data['platform']. Got None. (See <BASE_PATH>/fixtures/core/config/packages/configuration.yaml, line 16). ",
"Invalid config for [iot_domain.non_adr_0007]: expected str for dictionary value @ data['option1']. Got 123. (See <BASE_PATH>/fixtures/core/config/component_validation/packages/configuration.yaml, line 11). ",
"Invalid config for [iot_domain]: required key not provided @ data['platform']. Got None. (See <BASE_PATH>/fixtures/core/config/component_validation/packages/configuration.yaml, line 16). ",
"Invalid config for [adr_0007_2]: required key not provided @ data['adr_0007_2']['host']. Got None. (See ?, line ?). ",
"Invalid config for [adr_0007_3]: expected int for dictionary value @ data['adr_0007_3']['port']. Got 'foo'. (See ?, line ?). ",
])
# ---
# name: test_component_config_validation_error[packages_include_dir_named]
list([
"Invalid config for [iot_domain.non_adr_0007]: expected str for dictionary value @ data['option1']. Got 123. (See <BASE_PATH>/fixtures/core/config/packages_include_dir_named/integrations/iot_domain.yaml, line 6). ",
"Invalid config for [iot_domain]: required key not provided @ data['platform']. Got None. (See <BASE_PATH>/fixtures/core/config/packages_include_dir_named/integrations/iot_domain.yaml, line 9). ",
"Invalid config for [iot_domain.non_adr_0007]: expected str for dictionary value @ data['option1']. Got 123. (See <BASE_PATH>/fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 6). ",
"Invalid config for [iot_domain]: required key not provided @ data['platform']. Got None. (See <BASE_PATH>/fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 9). ",
"Invalid config for [adr_0007_2]: required key not provided @ data['adr_0007_2']['host']. Got None. (See ?, line ?). ",
"Invalid config for [adr_0007_3]: expected int for dictionary value @ data['adr_0007_3']['port']. Got 'foo'. (See ?, line ?). ",
])
# ---
# name: test_package_merge_error[packages]
list([
'Package pack_1 setup failed. Integration adr_0007_1 cannot be merged. Dict expected in main config. (See <BASE_PATH>/fixtures/core/config/package_errors/packages/configuration.yaml:9). ',
'Package pack_2 setup failed. Integration adr_0007_2 cannot be merged. Expected a dict. (See <BASE_PATH>/fixtures/core/config/package_errors/packages/configuration.yaml:13). ',
"Package pack_4 setup failed. Integration adr_0007_3 has duplicate key 'host' (See <BASE_PATH>/fixtures/core/config/package_errors/packages/configuration.yaml:20). ",
])
# ---
# name: test_package_merge_error[packages_include_dir_named]
list([
'Package adr_0007_1 setup failed. Integration adr_0007_1 cannot be merged. Dict expected in main config. (See <BASE_PATH>/fixtures/core/config/package_errors/packages_include_dir_named/integrations/adr_0007_1.yaml:2). ',
'Package adr_0007_2 setup failed. Integration adr_0007_2 cannot be merged. Expected a dict. (See <BASE_PATH>/fixtures/core/config/package_errors/packages_include_dir_named/integrations/adr_0007_2.yaml:2). ',
"Package adr_0007_3_2 setup failed. Integration adr_0007_3 has duplicate key 'host' (See <BASE_PATH>/fixtures/core/config/package_errors/packages_include_dir_named/integrations/adr_0007_3_2.yaml:1). ",
])
# ---
134 changes: 93 additions & 41 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from homeassistant.helpers import config_validation as cv, issue_registry as ir
import homeassistant.helpers.check_config as check_config
from homeassistant.helpers.entity import Entity
from homeassistant.loader import async_get_integration
from homeassistant.loader import Integration, async_get_integration
from homeassistant.util.unit_system import (
_CONF_UNIT_SYSTEM_US_CUSTOMARY,
METRIC_SYSTEM,
Expand Down Expand Up @@ -94,6 +94,66 @@ def teardown():
os.remove(SAFE_MODE_PATH)


IOT_DOMAIN_PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({vol.Remove("old"): str})


@pytest.fixture
async def mock_iot_domain_integration(hass: HomeAssistant) -> Integration:
"""Mock an integration which provides an IoT domain."""
comp_platform_schema = cv.PLATFORM_SCHEMA.extend({vol.Remove("old"): str})
comp_platform_schema_base = comp_platform_schema.extend({}, extra=vol.ALLOW_EXTRA)

return mock_integration(
hass,
MockModule(
"iot_domain",
platform_schema_base=comp_platform_schema_base,
platform_schema=comp_platform_schema,
),
)


@pytest.fixture
async def mock_non_adr_0007_integration(hass) -> None:
"""Mock a non-ADR-0007 compliant integration with iot_domain platform.

The integration allows setting up iot_domain entities under the iot_domain's
configuration key
"""

test_platform_schema = IOT_DOMAIN_PLATFORM_SCHEMA.extend({"option1": str})
mock_platform(
hass,
"non_adr_0007.iot_domain",
MockPlatform(platform_schema=test_platform_schema),
)


@pytest.fixture
async def mock_adr_0007_integrations(hass) -> list[Integration]:
"""Mock ADR-0007 compliant integrations."""
integrations = []
for domain in ["adr_0007_1", "adr_0007_2", "adr_0007_3"]:
adr_0007_config_schema = vol.Schema(
{
domain: vol.Schema(
{
vol.Required("host"): str,
vol.Required("port", default=8080): int,
}
)
},
extra=vol.ALLOW_EXTRA,
)
integrations.append(
mock_integration(
hass,
MockModule(domain, config_schema=adr_0007_config_schema),
)
)
return integrations


async def test_create_default_config(hass: HomeAssistant) -> None:
"""Test creation of default config."""
assert not os.path.isfile(YAML_PATH)
Expand Down Expand Up @@ -1425,52 +1485,16 @@ async def test_component_config_validation_error(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
config_dir: str,
mock_iot_domain_integration: Integration,
mock_non_adr_0007_integration: None,
mock_adr_0007_integrations: list[Integration],
snapshot: SnapshotAssertion,
) -> None:
"""Test schema error in component."""
comp_platform_schema = cv.PLATFORM_SCHEMA.extend({vol.Remove("old"): str})
comp_platform_schema_base = comp_platform_schema.extend({}, extra=vol.ALLOW_EXTRA)

# Mock an integration which provides an IoT domain
mock_integration(
hass,
MockModule(
"iot_domain",
platform_schema_base=comp_platform_schema_base,
platform_schema=comp_platform_schema,
),
)

# Mock a non-ADR-0007 compliant integration which allows setting up
# iot_domain entities under the iot_domain's configuration key
test_platform_schema = comp_platform_schema.extend({"option1": str})
mock_platform(
hass,
"non_adr_0007.iot_domain",
MockPlatform(platform_schema=test_platform_schema),
)

# Mock an ADR-0007 compliant integration
for domain in ["adr_0007_1", "adr_0007_2", "adr_0007_3"]:
adr_0007_config_schema = vol.Schema(
{
domain: vol.Schema(
{
vol.Required("host"): str,
vol.Required("port", default=8080): int,
}
)
},
extra=vol.ALLOW_EXTRA,
)
mock_integration(
hass,
MockModule(domain, config_schema=adr_0007_config_schema),
)

base_path = os.path.dirname(__file__)
hass.config.config_dir = os.path.join(
base_path, "fixtures", "core", "config", config_dir
base_path, "fixtures", "core", "config", "component_validation", config_dir
)
config = await config_util.async_hass_config_yaml(hass)

Expand All @@ -1488,3 +1512,31 @@ async def test_component_config_validation_error(
if record.levelno == logging.ERROR
]
assert error_records == snapshot


@pytest.mark.parametrize(
"config_dir",
["packages", "packages_include_dir_named"],
)
async def test_package_merge_error(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
config_dir: str,
mock_iot_domain_integration: Integration,
mock_non_adr_0007_integration: None,
mock_adr_0007_integrations: list[Integration],
snapshot: SnapshotAssertion,
) -> None:
"""Test schema error in component."""
base_path = os.path.dirname(__file__)
hass.config.config_dir = os.path.join(
base_path, "fixtures", "core", "config", "package_errors", config_dir
)
await config_util.async_hass_config_yaml(hass)

error_records = [
record.message.replace(base_path, "<BASE_PATH>")
for record in caplog.get_records("call")
if record.levelno == logging.ERROR
]
assert error_records == snapshot