From bc96f936563688f91527a140233e84d02f090805 Mon Sep 17 00:00:00 2001 From: vasanth064 Date: Fri, 28 Aug 2026 23:42:53 +0530 Subject: [PATCH 1/2] Alias azurerm_static_web_app and azurerm_cdn_frontdoor_* to existing icons Both icons already ship with Terravision but neither is reachable, so the resources render as generic unconnected nodes. - azurerm_static_site was renamed azurerm_static_web_app in the AzureRM provider. Only the old name was aliased, so current configurations miss static-apps.png. The legacy alias is kept for older configurations. - azurerm_cdn_frontdoor_* was never aliased, leaving FrontDoorAndCDNProfiles and front-door-and-cdn-profiles.png unreachable. Classic CDN is not an alternative for new work: creating azurerm_cdn_profile resources has been blocked since 1 October 2025, so Front Door is the only CDN path a current configuration can take. - Adds tests/test_azure_web_aliases.py, which fails without this change. No new icons or logic, aliases only. Co-Authored-By: Claude Opus 5 (1M context) --- resource_classes/azure/web.py | 6 ++++ tests/test_azure_web_aliases.py | 60 +++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 tests/test_azure_web_aliases.py diff --git a/resource_classes/azure/web.py b/resource_classes/azure/web.py index 749bc332..9337af55 100644 --- a/resource_classes/azure/web.py +++ b/resource_classes/azure/web.py @@ -99,3 +99,9 @@ class StaticApps(_Web): azurerm_search_service = Search azurerm_signalr_service = Signalr azurerm_static_site = StaticApps +azurerm_static_web_app = StaticApps +azurerm_cdn_frontdoor_profile = FrontDoorAndCDNProfiles +azurerm_cdn_frontdoor_endpoint = FrontDoorAndCDNProfiles +azurerm_cdn_frontdoor_origin_group = FrontDoorAndCDNProfiles +azurerm_cdn_frontdoor_origin = FrontDoorAndCDNProfiles +azurerm_cdn_frontdoor_route = FrontDoorAndCDNProfiles diff --git a/tests/test_azure_web_aliases.py b/tests/test_azure_web_aliases.py new file mode 100644 index 00000000..82571608 --- /dev/null +++ b/tests/test_azure_web_aliases.py @@ -0,0 +1,60 @@ +""" +Regression tests for Azure web resource aliases. + +Both icons these aliases reach already ship with Terravision, but the module +could not resolve either resource: + +- ``azurerm_static_site`` was renamed ``azurerm_static_web_app`` in the AzureRM + provider, and only the old name was aliased. +- ``azurerm_cdn_frontdoor_*`` was never aliased, so ``FrontDoorAndCDNProfiles`` + was unreachable. Classic CDN is not an alternative: creating new + ``azurerm_cdn_profile`` resources has been blocked since 1 October 2025. + +Without the aliases both render as generic unconnected nodes. +""" + +import pytest + +from resource_classes.azure import web + + +class TestStaticWebAppAlias: + def test_current_resource_name_is_aliased(self): + assert hasattr(web, "azurerm_static_web_app") + + def test_current_name_resolves_to_static_apps_icon(self): + assert web.azurerm_static_web_app is web.StaticApps + + def test_renamed_resource_keeps_the_legacy_alias(self): + assert web.azurerm_static_site is web.StaticApps + + +class TestFrontDoorAliases: + FRONT_DOOR_RESOURCES = [ + "azurerm_cdn_frontdoor_profile", + "azurerm_cdn_frontdoor_endpoint", + "azurerm_cdn_frontdoor_origin_group", + "azurerm_cdn_frontdoor_origin", + "azurerm_cdn_frontdoor_route", + ] + + @pytest.mark.parametrize("resource", FRONT_DOOR_RESOURCES) + def test_resource_is_aliased(self, resource): + assert hasattr(web, resource) + + @pytest.mark.parametrize("resource", FRONT_DOOR_RESOURCES) + def test_resource_resolves_to_front_door_icon(self, resource): + assert getattr(web, resource) is web.FrontDoorAndCDNProfiles + + +class TestAliasedIconsExist: + """An alias pointing at a class whose icon file is missing still renders blank.""" + + @pytest.mark.parametrize( + "icon_class", [web.StaticApps, web.FrontDoorAndCDNProfiles] + ) + def test_icon_file_is_present(self, icon_class): + from pathlib import Path + + icon = Path(web.__file__).parents[2] / icon_class._icon_dir / icon_class._icon + assert icon.is_file(), f"missing icon file: {icon}" From 5b0c3f6e264cd0917fdb542eb926394b6e13e9c3 Mon Sep 17 00:00:00 2001 From: vasanth064 Date: Fri, 28 Aug 2026 23:49:39 +0530 Subject: [PATCH 2/2] Point azure/databases.py at the directory its icons ship in _icon_dir read resource_images/azure/database while every icon the module names ships under resource_images/azure/databases. 41 of its 45 classes resolved to a file that does not exist. Nothing reported this. The alias resolved, so the renderer believed it had an icon and drew an empty node instead of warning. modules.drawing loads every module in the package into a single namespace, so the alphabetically last module wins. databases.py therefore overrode the working aliases in database.py, which is why azurerm_redis_cache and azurerm_postgresql_flexible_server rendered blank even though database.py mapped both to classes whose icons are present. Adds tests/test_azure_icon_dirs.py, which asserts every Azure class with an _icon points at a file that exists. It fails on exactly those 41 classes without this change. Co-Authored-By: Claude Opus 5 (1M context) --- resource_classes/azure/databases.py | 2 +- tests/test_azure_icon_dirs.py | 49 +++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 tests/test_azure_icon_dirs.py diff --git a/resource_classes/azure/databases.py b/resource_classes/azure/databases.py index e8e50a34..eae93ef3 100644 --- a/resource_classes/azure/databases.py +++ b/resource_classes/azure/databases.py @@ -3,7 +3,7 @@ class _Databases(_Azure): _type = "databases" - _icon_dir = "resource_images/azure/database" + _icon_dir = "resource_images/azure/databases" class AzureCosmosDb(_Databases): diff --git a/tests/test_azure_icon_dirs.py b/tests/test_azure_icon_dirs.py new file mode 100644 index 00000000..c600a56f --- /dev/null +++ b/tests/test_azure_icon_dirs.py @@ -0,0 +1,49 @@ +""" +Regression tests that every Azure resource class points at an icon that exists. + +``resource_classes/azure/databases.py`` declared ``resource_images/azure/database`` +while its icons ship under ``resource_images/azure/databases``, so 41 of its 45 +classes resolved to a missing file. Nothing warned about it: the alias resolved, +so the renderer believed it had an icon and drew an empty node. + +``modules.drawing`` loads every module in the package into one namespace, so the +alphabetically last module wins. That made ``databases.py`` override the working +aliases in ``database.py``, and broke azurerm_redis_cache and +azurerm_postgresql_flexible_server for anyone using them. +""" + +import importlib +import inspect +import pkgutil +from pathlib import Path + +import pytest + +import resource_classes.azure as azure_classes + +REPO_ROOT = Path(azure_classes.__file__).parents[2] + + +def _icon_classes(): + """Every class in resource_classes.azure that declares an icon.""" + found = [] + package_path = Path(azure_classes.__file__).parent + for _, module_name, _ in pkgutil.iter_modules([str(package_path)]): + module = importlib.import_module(f"resource_classes.azure.{module_name}") + for name, obj in vars(module).items(): + if inspect.isclass(obj) and getattr(obj, "_icon", None): + found.append(pytest.param(obj, id=f"{module_name}.{name}")) + return found + + +ICON_CLASSES = _icon_classes() + + +def test_azure_icon_classes_were_discovered(): + assert ICON_CLASSES, "no icon classes found; the package layout changed" + + +@pytest.mark.parametrize("icon_class", ICON_CLASSES) +def test_icon_file_exists(icon_class): + icon = REPO_ROOT / icon_class._icon_dir / icon_class._icon + assert icon.is_file(), f"{icon_class.__name__} points at missing icon {icon}"