Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion resource_classes/azure/databases.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

class _Databases(_Azure):
_type = "databases"
_icon_dir = "resource_images/azure/database"
_icon_dir = "resource_images/azure/databases"


class AzureCosmosDb(_Databases):
Expand Down
6 changes: 6 additions & 0 deletions resource_classes/azure/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
49 changes: 49 additions & 0 deletions tests/test_azure_icon_dirs.py
Original file line number Diff line number Diff line change
@@ -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}"
60 changes: 60 additions & 0 deletions tests/test_azure_web_aliases.py
Original file line number Diff line number Diff line change
@@ -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}"