Skip to content

Commit aa254e8

Browse files
Yet more tests
1 parent 265c63d commit aa254e8

File tree

1 file changed

+221
-63
lines changed

1 file changed

+221
-63
lines changed

tests/python/test_infrastructures.py

Lines changed: 221 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
Unit tests for infrastructures.py.
33
"""
44

5+
import json
6+
import os
57
from unittest.mock import Mock, patch, MagicMock
68
import pytest
79

@@ -2432,32 +2434,96 @@ def test_appgw_apim_pe_approve_private_links(mock_utils, mock_az):
24322434
assert isinstance(result, bool)
24332435

24342436

2435-
def test_afd_apim_aca_disable_public_access(mock_utils, mock_az):
2436-
"""Test disabling public access for AfdApimAcaInfrastructure."""
2437-
infra = infrastructures.AfdApimAcaInfrastructure(
2438-
rg_location='eastus',
2439-
index=1
2437+
@pytest.mark.unit
2438+
def test_disable_apim_public_access_success_writes_params_and_calls_az(mock_utils, mock_az, tmp_path, monkeypatch):
2439+
"""Disable public access should update params.json and trigger a redeploy."""
2440+
infra = infrastructures.AfdApimAcaInfrastructure(rg_location='eastus', index=1)
2441+
2442+
infra._define_policy_fragments()
2443+
infra._define_apis()
2444+
infra._define_bicep_parameters()
2445+
assert infra.bicep_parameters['apimPublicAccess']['value'] is True
2446+
2447+
# Redirect module-relative path resolution to a temp project layout.
2448+
monkeypatch.setattr(
2449+
infrastructures,
2450+
'__file__',
2451+
str(tmp_path / 'shared' / 'python' / 'infrastructures.py'),
2452+
raising=False
24402453
)
2454+
infra_dir = tmp_path / 'infrastructure' / infra.infra.value
2455+
infra_dir.mkdir(parents=True, exist_ok=True)
24412456

24422457
mock_az.run.return_value = Mock(success=True)
24432458

2459+
original_cwd = os.getcwd()
24442460
result = infra._disable_apim_public_access()
24452461

2446-
assert isinstance(result, bool)
2462+
assert result is True
2463+
assert os.getcwd() == original_cwd
2464+
assert infra.bicep_parameters['apimPublicAccess']['value'] is False
24472465

2466+
params_path = infra_dir / 'params.json'
2467+
assert params_path.exists()
24482468

2449-
def test_appgw_apim_pe_disable_public_access(mock_utils, mock_az):
2450-
"""Test disabling public access for AppGwApimPeInfrastructure."""
2451-
infra = infrastructures.AppGwApimPeInfrastructure(
2452-
rg_location='eastus',
2453-
index=1
2469+
params_json = json.loads(params_path.read_text(encoding='utf-8'))
2470+
assert params_json['parameters']['apimPublicAccess']['value'] is False
2471+
2472+
mock_az.run.assert_called_once()
2473+
cmd = mock_az.run.call_args.args[0]
2474+
assert 'az deployment group create' in cmd
2475+
assert f'--name {infra.infra.value}-lockdown' in cmd
2476+
assert f'--resource-group {infra.rg_name}' in cmd
2477+
assert '--template-file' in cmd
2478+
assert '--parameters' in cmd
2479+
2480+
2481+
@pytest.mark.unit
2482+
def test_disable_apim_public_access_returns_false_when_param_missing(mock_utils, mock_az):
2483+
"""If apimPublicAccess isn't present in parameters, the method should fail safely."""
2484+
infra = infrastructures.Infrastructure(
2485+
infra=INFRASTRUCTURE.SIMPLE_APIM,
2486+
index=1,
2487+
rg_location='eastus'
24542488
)
24552489

2456-
mock_az.run.return_value = Mock(success=True)
2490+
infra._define_policy_fragments()
2491+
infra._define_apis()
2492+
infra._define_bicep_parameters()
2493+
assert 'apimPublicAccess' not in infra.bicep_parameters
24572494

24582495
result = infra._disable_apim_public_access()
24592496

2460-
assert isinstance(result, bool)
2497+
assert result is False
2498+
mock_az.run.assert_not_called()
2499+
2500+
2501+
@pytest.mark.unit
2502+
def test_disable_apim_public_access_returns_false_when_deploy_fails(mock_utils, mock_az, tmp_path, monkeypatch):
2503+
"""If the redeploy fails (az.run.success=False), return False but still write params.json."""
2504+
infra = infrastructures.AppGwApimPeInfrastructure(rg_location='eastus', index=1)
2505+
2506+
infra._define_policy_fragments()
2507+
infra._define_apis()
2508+
infra._define_bicep_parameters()
2509+
assert infra.bicep_parameters['apimPublicAccess']['value'] is True
2510+
2511+
monkeypatch.setattr(
2512+
infrastructures,
2513+
'__file__',
2514+
str(tmp_path / 'shared' / 'python' / 'infrastructures.py'),
2515+
raising=False
2516+
)
2517+
infra_dir = tmp_path / 'infrastructure' / infra.infra.value
2518+
infra_dir.mkdir(parents=True, exist_ok=True)
2519+
2520+
mock_az.run.return_value = Mock(success=False)
2521+
2522+
result = infra._disable_apim_public_access()
2523+
2524+
assert result is False
2525+
assert (infra_dir / 'params.json').exists()
2526+
assert infra.bicep_parameters['apimPublicAccess']['value'] is False
24612527

24622528

24632529
def test_afd_apim_aca_verify_connectivity(mock_utils, mock_az):
@@ -2712,32 +2778,156 @@ def test_appgw_apim_pe_approve_private_links_multiple(mock_utils, mock_az):
27122778
assert isinstance(result, bool)
27132779

27142780

2715-
def test_afd_apim_aca_disable_public_access_success(mock_utils, mock_az):
2716-
"""Test disabling public access for AfdApimAcaInfrastructure."""
2717-
infra = infrastructures.AfdApimAcaInfrastructure(
2718-
rg_location='eastus',
2719-
index=1
2720-
)
2781+
@pytest.mark.unit
2782+
def test_afd_apim_aca_deploy_infrastructure_success_calls_steps(mock_utils, mock_az):
2783+
"""AFD deploy should call approve/connectivity/disable steps when base deploy succeeds."""
2784+
mock_utils.Output.side_effect = Output
27212785

2722-
mock_az.run.return_value = Mock(success=True)
2786+
infra = infrastructures.AfdApimAcaInfrastructure(rg_location='eastus', index=1)
27232787

2724-
result = infra._disable_apim_public_access()
2788+
base_output = Mock()
2789+
base_output.success = True
2790+
base_output.json_data = {'any': 'value'}
2791+
base_output.get.side_effect = lambda key, *_args, **_kwargs: {
2792+
'apimServiceId': '/subscriptions/test/resourceGroups/test/providers/Microsoft.ApiManagement/service/test',
2793+
'apimResourceGatewayURL': 'https://test-apim.azure-api.net'
2794+
}.get(key)
27252795

2726-
assert isinstance(result, bool)
2796+
infra._approve_private_link_connections = Mock(return_value=True)
2797+
infra._verify_apim_connectivity = Mock(return_value=True)
2798+
infra._disable_apim_public_access = Mock(return_value=True)
27272799

2800+
with patch.object(infrastructures.Infrastructure, 'deploy_infrastructure', return_value=base_output) as mock_base_deploy:
2801+
result = infra.deploy_infrastructure(is_update=False)
27282802

2729-
def test_appgw_apim_pe_disable_public_access_success(mock_utils, mock_az):
2730-
"""Test disabling public access for AppGwApimPeInfrastructure."""
2731-
infra = infrastructures.AppGwApimPeInfrastructure(
2732-
rg_location='eastus',
2733-
index=1
2734-
)
2803+
assert result is base_output
2804+
mock_base_deploy.assert_called_once()
2805+
infra._approve_private_link_connections.assert_called_once_with('/subscriptions/test/resourceGroups/test/providers/Microsoft.ApiManagement/service/test')
2806+
infra._verify_apim_connectivity.assert_called_once_with('https://test-apim.azure-api.net')
2807+
infra._disable_apim_public_access.assert_called_once()
27352808

2736-
mock_az.run.return_value = Mock(success=True)
27372809

2738-
result = infra._disable_apim_public_access()
2810+
@pytest.mark.unit
2811+
def test_afd_apim_aca_deploy_infrastructure_returns_failed_output_when_approve_fails(mock_utils, mock_az):
2812+
"""AFD deploy should return a failed Output when private link approval fails."""
2813+
mock_utils.Output.side_effect = Output
27392814

2740-
assert isinstance(result, bool)
2815+
infra = infrastructures.AfdApimAcaInfrastructure(rg_location='eastus', index=1)
2816+
2817+
base_output = Mock()
2818+
base_output.success = True
2819+
base_output.json_data = {'any': 'value'}
2820+
base_output.get.side_effect = lambda key, *_args, **_kwargs: {
2821+
'apimServiceId': '/subscriptions/test/resourceGroups/test/providers/Microsoft.ApiManagement/service/test',
2822+
'apimResourceGatewayURL': 'https://test-apim.azure-api.net'
2823+
}.get(key)
2824+
2825+
infra._approve_private_link_connections = Mock(return_value=False)
2826+
2827+
with patch.object(infrastructures.Infrastructure, 'deploy_infrastructure', return_value=base_output):
2828+
result = infra.deploy_infrastructure(is_update=False)
2829+
2830+
assert result.success is False
2831+
assert result.text == 'Private link approval failed'
2832+
2833+
2834+
@pytest.mark.unit
2835+
def test_appgw_apim_pe_deploy_infrastructure_success_calls_steps_and_sets_appgw_fields(mock_utils, mock_az):
2836+
"""APPGW PE deploy should create prereqs, deploy, approve, verify connectivity, disable public access."""
2837+
mock_utils.Output.side_effect = Output
2838+
2839+
infra = infrastructures.AppGwApimPeInfrastructure(rg_location='eastus', index=1)
2840+
2841+
base_output = Mock()
2842+
base_output.success = True
2843+
base_output.json_data = {'any': 'value'}
2844+
base_output.get.side_effect = lambda key, *_args, **_kwargs: {
2845+
'apimServiceId': '/subscriptions/test/resourceGroups/test/providers/Microsoft.ApiManagement/service/test',
2846+
'apimResourceGatewayURL': 'https://test-apim.azure-api.net',
2847+
'appGatewayDomainName': 'api.example.com',
2848+
'appgwPublicIpAddress': '1.2.3.4'
2849+
}.get(key)
2850+
2851+
infra._create_keyvault = Mock(return_value=True)
2852+
infra._create_keyvault_certificate = Mock(return_value=True)
2853+
infra._approve_private_link_connections = Mock(return_value=True)
2854+
infra._verify_apim_connectivity = Mock(return_value=True)
2855+
infra._disable_apim_public_access = Mock(return_value=True)
2856+
2857+
with patch.object(infrastructures.Infrastructure, 'deploy_infrastructure', return_value=base_output) as mock_base_deploy:
2858+
result = infra.deploy_infrastructure(is_update=False)
2859+
2860+
assert result is base_output
2861+
infra._create_keyvault.assert_called_once()
2862+
infra._create_keyvault_certificate.assert_called_once()
2863+
mock_base_deploy.assert_called_once()
2864+
infra._approve_private_link_connections.assert_called_once_with('/subscriptions/test/resourceGroups/test/providers/Microsoft.ApiManagement/service/test')
2865+
infra._verify_apim_connectivity.assert_called_once_with('https://test-apim.azure-api.net')
2866+
infra._disable_apim_public_access.assert_called_once()
2867+
assert infra.appgw_domain_name == 'api.example.com'
2868+
assert infra.appgw_public_ip == '1.2.3.4'
2869+
2870+
2871+
@pytest.mark.unit
2872+
def test_appgw_apim_pe_deploy_infrastructure_returns_failed_output_when_keyvault_fails(mock_utils, mock_az):
2873+
"""APPGW PE deploy should return a failed Output if Key Vault creation fails."""
2874+
mock_utils.Output.side_effect = Output
2875+
2876+
infra = infrastructures.AppGwApimPeInfrastructure(rg_location='eastus', index=1)
2877+
infra._create_keyvault = Mock(return_value=False)
2878+
2879+
result = infra.deploy_infrastructure(is_update=False)
2880+
2881+
assert result.success is False
2882+
assert result.text == 'Failed to create Key Vault'
2883+
2884+
2885+
@pytest.mark.unit
2886+
def test_appgw_apim_pe_verify_infrastructure_specific_success(mock_utils, mock_az):
2887+
"""Verify should pass when App Gateway exists; container apps and PE checks are optional."""
2888+
infra = infrastructures.AppGwApimPeInfrastructure(rg_location='eastus', index=1)
2889+
2890+
appgw_output = Mock(success=True, json_data={'name': 'test-appgw'})
2891+
aca_output = Mock(success=True, text='1')
2892+
apim_output = Mock(success=True, text='/subscriptions/test/.../apim')
2893+
pe_output = Mock(success=True, text='2')
2894+
2895+
mock_az.run.side_effect = [appgw_output, aca_output, apim_output, pe_output]
2896+
2897+
assert infra._verify_infrastructure_specific('rg-test') is True
2898+
2899+
2900+
@pytest.mark.unit
2901+
def test_appgw_apim_pe_verify_infrastructure_specific_returns_false_when_appgw_missing(mock_utils, mock_az):
2902+
"""Verify should fail when App Gateway cannot be retrieved."""
2903+
infra = infrastructures.AppGwApimPeInfrastructure(rg_location='eastus', index=1)
2904+
2905+
mock_az.run.return_value = Mock(success=False, json_data=None)
2906+
2907+
assert infra._verify_infrastructure_specific('rg-test') is False
2908+
2909+
2910+
@pytest.mark.unit
2911+
def test_appgw_apim_pe_verify_infrastructure_specific_ignores_private_endpoint_errors(mock_utils, mock_az):
2912+
"""Private endpoint verification is best-effort and should not fail the overall verification."""
2913+
infra = infrastructures.AppGwApimPeInfrastructure(rg_location='eastus', index=1)
2914+
2915+
appgw_output = Mock(success=True, json_data={'name': 'test-appgw'})
2916+
aca_output = Mock(success=True, text='0')
2917+
2918+
def run_side_effect(*args, **kwargs):
2919+
cmd = args[0] if args else ''
2920+
if 'application-gateway list' in cmd:
2921+
return appgw_output
2922+
if 'containerapp list' in cmd:
2923+
return aca_output
2924+
if 'az apim list' in cmd:
2925+
raise RuntimeError('boom')
2926+
raise AssertionError(f'Unexpected az.run call: {cmd}')
2927+
2928+
mock_az.run.side_effect = run_side_effect
2929+
2930+
assert infra._verify_infrastructure_specific('rg-test') is True
27412931

27422932

27432933
def test_afd_apim_aca_verify_connectivity_with_retry(mock_utils, mock_az):
@@ -2959,35 +3149,3 @@ def test_infrastructure_network_mode_with_custom_components(mock_utils):
29593149
infra._define_apis()
29603150
assert len(infra.pfs) == 7
29613151
assert len(infra.apis) == 2
2962-
2963-
2964-
def test_infrastructure_account_info_retrieval(mock_utils, mock_az):
2965-
"""Test that account info is properly retrieved and stored."""
2966-
mock_az.get_account_info.return_value = (
2967-
2968-
'user-id-12345',
2969-
'tenant-id-67890',
2970-
'subscription-id-abcde'
2971-
)
2972-
2973-
infra = infrastructures.Infrastructure(
2974-
infra=INFRASTRUCTURE.SIMPLE_APIM,
2975-
index=1,
2976-
rg_location='eastus'
2977-
)
2978-
2979-
assert infra.current_user == '[email protected]'
2980-
assert infra.current_user_id == 'user-id-12345'
2981-
assert infra.tenant_id == 'tenant-id-67890'
2982-
assert infra.subscription_id == 'subscription-id-abcde'
2983-
2984-
2985-
def test_infrastructure_with_different_indices(mock_utils):
2986-
"""Test infrastructure with different index values."""
2987-
for index in [1, 2, 5, 10, 100]:
2988-
infra = infrastructures.Infrastructure(
2989-
infra=INFRASTRUCTURE.SIMPLE_APIM,
2990-
index=index,
2991-
rg_location='eastus'
2992-
)
2993-
assert infra.index == index

0 commit comments

Comments
 (0)