Files
apim-apps/tests/test_normalize.py
T
2026-06-29 14:22:37 +02:00

199 lines
7.0 KiB
Python

import pytest
from unittest.mock import MagicMock, patch
from apim_apps import normalize_env, EnvConfig, Manifest, OrgSpec, AppSpec, ApiAccess
@pytest.fixture
def env():
return EnvConfig(name="TEST", url="https://test.example.com:8075", username="u", password="p")
@pytest.fixture
def mock_client():
with patch("apim_apps.engine.AxwayClient") as MockClient:
instance = MockClient.return_value
instance.list_orgs.return_value = {}
instance.list_apps.return_value = {}
instance.list_app_api_access.return_value = []
yield instance
def _manifest(orgs=None, apps=None):
return Manifest(organizations=orgs or [], applications=apps or [])
# ---------------------------------------------------------------------------
# Dry-run
# ---------------------------------------------------------------------------
def test_dry_run_makes_no_api_calls(env, mock_client):
manifest = _manifest(
orgs=[OrgSpec(name="MyOrg")],
apps=[AppSpec(name="MyApp", org_name="MyOrg", apis=[ApiAccess(api_name="MyAPI")])],
)
mock_client.list_orgs.return_value = {}
mock_client.list_apps.return_value = {}
result = normalize_env(env, manifest, dry_run=True)
mock_client.create_org.assert_not_called()
mock_client.create_app.assert_not_called()
mock_client.grant_api_access.assert_not_called()
assert len(result.errors) == 0
def test_dry_run_reports_planned_actions(env, mock_client):
manifest = _manifest(
orgs=[OrgSpec(name="MyOrg")],
apps=[AppSpec(name="MyApp", org_name="MyOrg")],
)
result = normalize_env(env, manifest, dry_run=True)
kinds = {a.kind for a in result.actions_done}
assert "create_org" in kinds
assert "create_app" in kinds
# ---------------------------------------------------------------------------
# Apply mode
# ---------------------------------------------------------------------------
def test_apply_creates_org_and_app(env, mock_client):
manifest = _manifest(
orgs=[OrgSpec(name="MyOrg")],
apps=[AppSpec(name="MyApp", org_name="MyOrg")],
)
mock_client.create_org.return_value = {"id": "org-1", "name": "MyOrg"}
mock_client.create_app.return_value = {"id": "app-1", "name": "MyApp"}
result = normalize_env(env, manifest, dry_run=False)
mock_client.create_org.assert_called_once()
mock_client.create_app.assert_called_once()
assert len(result.errors) == 0
def test_apply_grants_api_subscription(env, mock_client):
manifest = _manifest(
orgs=[OrgSpec(name="MyOrg")],
apps=[AppSpec(name="MyApp", org_name="MyOrg", apis=[ApiAccess(api_name="MyAPI")])],
)
mock_client.create_org.return_value = {"id": "org-1", "name": "MyOrg"}
mock_client.create_app.return_value = {"id": "app-1", "name": "MyApp"}
mock_client.find_frontend_api.return_value = {"id": "api-1", "name": "MyAPI"}
normalize_env(env, manifest, dry_run=False)
mock_client.grant_api_access.assert_called_once_with("app-1", "api-1")
def test_apply_skips_missing_frontend_api(env, mock_client):
manifest = _manifest(
orgs=[OrgSpec(name="MyOrg")],
apps=[AppSpec(name="MyApp", org_name="MyOrg", apis=[ApiAccess(api_name="Ghost")])],
)
mock_client.create_org.return_value = {"id": "org-1", "name": "MyOrg"}
mock_client.create_app.return_value = {"id": "app-1", "name": "MyApp"}
mock_client.find_frontend_api.return_value = None
result = normalize_env(env, manifest, dry_run=False)
mock_client.grant_api_access.assert_not_called()
assert any("Ghost" in e for e in result.errors)
# ---------------------------------------------------------------------------
# Skip when already present
# ---------------------------------------------------------------------------
def test_skips_existing_org(env, mock_client):
manifest = _manifest(orgs=[OrgSpec(name="MyOrg")])
mock_client.list_orgs.return_value = {"MyOrg": {"id": "org-1", "name": "MyOrg"}}
result = normalize_env(env, manifest, dry_run=False)
mock_client.create_org.assert_not_called()
assert any(a.kind == "create_org" for a in result.actions_skipped)
def test_skips_existing_app(env, mock_client):
manifest = _manifest(
orgs=[OrgSpec(name="MyOrg")],
apps=[AppSpec(name="MyApp", org_name="MyOrg")],
)
mock_client.list_orgs.return_value = {"MyOrg": {"id": "org-1", "name": "MyOrg"}}
mock_client.list_apps.return_value = {("MyOrg", "MyApp"): {"id": "app-1", "name": "MyApp"}}
result = normalize_env(env, manifest, dry_run=False)
mock_client.create_app.assert_not_called()
assert any(a.kind == "create_app" for a in result.actions_skipped)
def test_skips_already_granted_api(env, mock_client):
manifest = _manifest(
orgs=[OrgSpec(name="MyOrg")],
apps=[AppSpec(name="MyApp", org_name="MyOrg", apis=[ApiAccess(api_name="MyAPI")])],
)
mock_client.list_orgs.return_value = {"MyOrg": {"id": "org-1", "name": "MyOrg"}}
mock_client.list_apps.return_value = {("MyOrg", "MyApp"): {"id": "app-1", "name": "MyApp"}}
mock_client.list_app_api_access.return_value = [{"apiName": "MyAPI", "id": "api-1"}]
result = normalize_env(env, manifest, dry_run=False)
mock_client.grant_api_access.assert_not_called()
assert any(a.kind == "grant_api" for a in result.actions_skipped)
# ---------------------------------------------------------------------------
# Environment filtering
# ---------------------------------------------------------------------------
def test_env_filter_excludes_other_env(env, mock_client):
manifest = _manifest(
orgs=[
OrgSpec(name="GlobalOrg"),
OrgSpec(name="ProdOnly", environments=["PROD"]),
]
)
result = normalize_env(env, manifest, dry_run=True)
org_names = [a.detail["org"] for a in result.actions_done + result.actions_skipped]
assert "GlobalOrg" in org_names
assert "ProdOnly" not in org_names
def test_env_filter_matches_current_env(env, mock_client):
manifest = _manifest(
orgs=[OrgSpec(name="TestOnly", environments=["TEST"])]
)
result = normalize_env(env, manifest, dry_run=True)
org_names = [a.detail["org"] for a in result.actions_done + result.actions_skipped]
assert "TestOnly" in org_names
# ---------------------------------------------------------------------------
# Error handling
# ---------------------------------------------------------------------------
def test_error_when_org_missing_for_app(env, mock_client):
manifest = _manifest(
apps=[AppSpec(name="Orphan", org_name="MissingOrg")]
)
mock_client.list_orgs.return_value = {}
result = normalize_env(env, manifest, dry_run=False)
assert any("MissingOrg" in e for e in result.errors)
def test_list_orgs_failure_returns_error(env, mock_client):
import requests
mock_client.list_orgs.side_effect = requests.ConnectionError("timeout")
manifest = _manifest(orgs=[OrgSpec(name="MyOrg")])
result = normalize_env(env, manifest, dry_run=False)
assert len(result.errors) == 1