From 5d6b6deed4374865143d182b5dd63a4b8a362388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Tue, 1 Jun 2021 00:32:03 +0200 Subject: [PATCH] Move version validation to resolver (#51311) --- homeassistant/loader.py | 60 +++++++++---------- tests/test_loader.py | 57 +++++++----------- .../test_bad_version/__init__.py | 1 + .../test_bad_version/manifest.json | 4 ++ .../test_no_version/__init__.py | 1 + .../test_no_version/manifest.json | 3 + 6 files changed, 58 insertions(+), 68 deletions(-) create mode 100644 tests/testing_config/custom_components/test_bad_version/__init__.py create mode 100644 tests/testing_config/custom_components/test_bad_version/manifest.json create mode 100644 tests/testing_config/custom_components/test_no_version/__init__.py create mode 100644 tests/testing_config/custom_components/test_no_version/manifest.json diff --git a/homeassistant/loader.py b/homeassistant/loader.py index 444e35add333..06bf5045c9fa 100644 --- a/homeassistant/loader.py +++ b/homeassistant/loader.py @@ -47,7 +47,7 @@ DATA_CUSTOM_COMPONENTS = "custom_components" PACKAGE_CUSTOM_COMPONENTS = "custom_components" PACKAGE_BUILTIN = "homeassistant.components" CUSTOM_WARNING = ( - "You are using a custom integration %s which has not " + "We found a custom integration %s which has not " "been tested by Home Assistant. This component might " "cause stability problems, be sure to disable it if you " "experience issues with Home Assistant" @@ -290,13 +290,39 @@ class Integration: ) continue - return cls( + integration = cls( hass, f"{root_module.__name__}.{domain}", manifest_path.parent, manifest, ) + if integration.is_built_in: + return integration + + _LOGGER.warning(CUSTOM_WARNING, integration.domain) + try: + AwesomeVersion( + integration.version, + [ + AwesomeVersionStrategy.CALVER, + AwesomeVersionStrategy.SEMVER, + AwesomeVersionStrategy.SIMPLEVER, + AwesomeVersionStrategy.BUILDVER, + AwesomeVersionStrategy.PEP440, + ], + ) + except AwesomeVersionException: + _LOGGER.error( + "The custom integration '%s' does not have a " + "valid version key (%s) in the manifest file and was blocked from loading. " + "See https://developers.home-assistant.io/blog/2021/01/29/custom-integration-changes#versions for more details", + integration.domain, + integration.version, + ) + return None + return integration + return None def __init__( @@ -523,8 +549,6 @@ async def _async_get_integration(hass: HomeAssistant, domain: str) -> Integratio # Instead of using resolve_from_root we use the cache of custom # components to find the integration. if integration := (await async_get_custom_components(hass)).get(domain): - validate_custom_integration_version(integration) - _LOGGER.warning(CUSTOM_WARNING, integration.domain) return integration from homeassistant import components # pylint: disable=import-outside-toplevel @@ -744,31 +768,3 @@ def _lookup_path(hass: HomeAssistant) -> list[str]: if hass.config.safe_mode: return [PACKAGE_BUILTIN] return [PACKAGE_CUSTOM_COMPONENTS, PACKAGE_BUILTIN] - - -def validate_custom_integration_version(integration: Integration) -> None: - """ - Validate the version of custom integrations. - - Raises IntegrationNotFound when version is missing or not valid - """ - try: - AwesomeVersion( - integration.version, - [ - AwesomeVersionStrategy.CALVER, - AwesomeVersionStrategy.SEMVER, - AwesomeVersionStrategy.SIMPLEVER, - AwesomeVersionStrategy.BUILDVER, - AwesomeVersionStrategy.PEP440, - ], - ) - except AwesomeVersionException: - _LOGGER.error( - "The custom integration '%s' does not have a " - "valid version key (%s) in the manifest file and was blocked from loading. " - "See https://developers.home-assistant.io/blog/2021/01/29/custom-integration-changes#versions for more details", - integration.domain, - integration.version, - ) - raise IntegrationNotFound(integration.domain) from None diff --git a/tests/test_loader.py b/tests/test_loader.py index e696f27351d9..20dcf90d90eb 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -127,37 +127,30 @@ async def test_log_warning_custom_component(hass, caplog, enable_custom_integrat """Test that we log a warning when loading a custom component.""" await loader.async_get_integration(hass, "test_package") - assert "You are using a custom integration test_package" in caplog.text + assert "We found a custom integration test_package" in caplog.text await loader.async_get_integration(hass, "test") - assert "You are using a custom integration test " in caplog.text + assert "We found a custom integration test " in caplog.text -async def test_custom_integration_version_not_valid(hass, caplog): +async def test_custom_integration_version_not_valid( + hass, caplog, enable_custom_integrations +): """Test that we log a warning when custom integrations have a invalid version.""" - test_integration1 = loader.Integration( - hass, "custom_components.test", None, {"domain": "test1", "version": "test"} - ) - test_integration2 = loader.Integration( - hass, "custom_components.test", None, {"domain": "test2"} + with pytest.raises(loader.IntegrationNotFound): + await loader.async_get_integration(hass, "test_no_version") + + assert ( + "The custom integration 'test_no_version' does not have a valid version key (None) in the manifest file and was blocked from loading." + in caplog.text ) - with patch("homeassistant.loader.async_get_custom_components") as mock_get: - mock_get.return_value = {"test1": test_integration1, "test2": test_integration2} - - with pytest.raises(loader.IntegrationNotFound): - await loader.async_get_integration(hass, "test1") - assert ( - "The custom integration 'test1' does not have a valid version key (test) in the manifest file and was blocked from loading." - in caplog.text - ) - - with pytest.raises(loader.IntegrationNotFound): - await loader.async_get_integration(hass, "test2") - assert ( - "The custom integration 'test2' does not have a valid version key (None) in the manifest file and was blocked from loading." - in caplog.text - ) + with pytest.raises(loader.IntegrationNotFound): + await loader.async_get_integration(hass, "test2") + assert ( + "The custom integration 'test_bad_version' does not have a valid version key (bad) in the manifest file and was blocked from loading." + in caplog.text + ) async def test_get_integration(hass): @@ -471,19 +464,11 @@ async def test_get_custom_components_safe_mode(hass): async def test_custom_integration_missing_version(hass, caplog): """Test trying to load a custom integration without a version twice does not deadlock.""" - test_integration_1 = loader.Integration( - hass, "custom_components.test1", None, {"domain": "test1"} - ) - with patch("homeassistant.loader.async_get_custom_components") as mock_get: - mock_get.return_value = { - "test1": test_integration_1, - } + with pytest.raises(loader.IntegrationNotFound): + await loader.async_get_integration(hass, "test_no_version") - with pytest.raises(loader.IntegrationNotFound): - await loader.async_get_integration(hass, "test1") - - with pytest.raises(loader.IntegrationNotFound): - await loader.async_get_integration(hass, "test1") + with pytest.raises(loader.IntegrationNotFound): + await loader.async_get_integration(hass, "test_no_version") async def test_custom_integration_missing(hass, caplog): diff --git a/tests/testing_config/custom_components/test_bad_version/__init__.py b/tests/testing_config/custom_components/test_bad_version/__init__.py new file mode 100644 index 000000000000..e39053682e37 --- /dev/null +++ b/tests/testing_config/custom_components/test_bad_version/__init__.py @@ -0,0 +1 @@ +"""Provide a mock integration.""" diff --git a/tests/testing_config/custom_components/test_bad_version/manifest.json b/tests/testing_config/custom_components/test_bad_version/manifest.json new file mode 100644 index 000000000000..69d322a33adb --- /dev/null +++ b/tests/testing_config/custom_components/test_bad_version/manifest.json @@ -0,0 +1,4 @@ +{ + "domain": "test_bad_version", + "version": "bad" +} \ No newline at end of file diff --git a/tests/testing_config/custom_components/test_no_version/__init__.py b/tests/testing_config/custom_components/test_no_version/__init__.py new file mode 100644 index 000000000000..e39053682e37 --- /dev/null +++ b/tests/testing_config/custom_components/test_no_version/__init__.py @@ -0,0 +1 @@ +"""Provide a mock integration.""" diff --git a/tests/testing_config/custom_components/test_no_version/manifest.json b/tests/testing_config/custom_components/test_no_version/manifest.json new file mode 100644 index 000000000000..9054cf4f5e37 --- /dev/null +++ b/tests/testing_config/custom_components/test_no_version/manifest.json @@ -0,0 +1,3 @@ +{ + "domain": "test_no_version" +} \ No newline at end of file