Skip to content

Commit fe8e6c8

Browse files
committed
fix: replace broken Phase 4/5 placeholder tests with real test coverage
Both test files were unskipped placeholder stubs — they referenced undefined symbols (load_spec, Orchestrator, RuntimeState.load, get_supabase) and contained no executable assertions. The handlers themselves (PlatformIdentityPhaseHandler and RegistriesPhaseHandler) were already fully implemented. The blockers were the tests that gated them as "not yet implemented". New test_phase4_platform.py (10 tests): - execute() populates identity_platform_output with all required keys - phase_completed["4"] set to True after execute - Keycloak container ID persisted to runtime_state - auth.platform.internal A record registered via DNSHandler - Bootstrap admin password generated / reused from state - TLS cert issued for auth.platform.internal via PKIHandler - Platform realm created via OIDCHandler - Realm/user/client IDs persisted to runtime_state New test_phase5_registries.py (11 tests): - execute() populates world_registry_output and domain_registry_output - Both outputs have all required keys - phase_completed["5"] set to True - WorldRegistryHandler.seed_from_spec called with spec - DomainRegistryHandler.seed_address_pools called with spec - WHOIS server registered with consumer_supervisor - dns_updates consumer registered with consumer_supervisor - NS + A zone records created for each configured TLD - TLD delegation data recorded in output Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YTMfjdVS2v1g6gyLbY1kA5
1 parent 3c6d27c commit fe8e6c8

2 files changed

Lines changed: 358 additions & 53 deletions

File tree

Lines changed: 169 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,172 @@
1-
import asyncio
1+
"""Integration tests for Phase 4: Platform Identity (Keycloak + Supabase).
2+
3+
Covers execute() behaviour with mocked infrastructure — the interface contract
4+
(should_skip / healthcheck) is already exercised in test_m3_bootstrap.py.
5+
"""
6+
7+
from unittest.mock import AsyncMock, MagicMock, mock_open, patch
28

39
import pytest
410

5-
pytestmark = pytest.mark.skip(reason="Phase 4 handlers not yet implemented (M3+)")
6-
7-
8-
@pytest.mark.asyncio
9-
async def test_phase_4():
10-
# Load spec, run phases 0-3 (stubbed) and then phase 4
11-
spec = load_spec("examples/minimal.yaml")
12-
orch = Orchestrator(spec)
13-
# Assume phases 0-3 are already run (or call them)
14-
await orch.phase_3_pki() # if not run
15-
# Now run Phase 4 handler directly
16-
from netengine.phases.phase_platform_identity import PlatformIdentityPhaseHandler
17-
18-
handler = PlatformIdentityPhaseHandler()
19-
await handler.execute(orch.context)
20-
21-
# Verify:
22-
state = RuntimeState.load()
23-
assert state.keycloak_platform_container_id is not None
24-
assert state.platform_realm_id == "platform"
25-
# Check DNS: dig auth.platform.internal
26-
# Check Keycloak reachable: curl -k https://auth.platform.internal/health/ready
27-
# Check admin user can get token
11+
from netengine.phases.phase_platform_identity import PlatformIdentityPhaseHandler
12+
13+
14+
@pytest.fixture
15+
def patched_platform_deps(phase_context):
16+
"""Phase context with all Phase 4 external dependencies mocked out."""
17+
mock_pki = MagicMock()
18+
mock_pki.issue_cert = AsyncMock(return_value=("CERT-DATA", "KEY-DATA"))
19+
20+
mock_docker = MagicMock()
21+
mock_docker.start_container = AsyncMock(return_value="keycloak-ctr-abc")
22+
23+
mock_oidc = MagicMock()
24+
mock_oidc.create_platform_realm = AsyncMock(return_value="platform-realm-id")
25+
mock_oidc.create_admin_user = AsyncMock(return_value="admin-user-id")
26+
mock_oidc.create_client = AsyncMock(return_value="platform-api-client-id")
27+
mock_oidc.add_token_mapper = AsyncMock()
28+
29+
mock_dns = MagicMock()
30+
mock_dns.add_zone_record = AsyncMock()
31+
32+
patches = [
33+
patch("netengine.phases.phase_platform_identity.apply_migrations", AsyncMock()),
34+
patch(
35+
"netengine.phases.phase_platform_identity.PKIHandler",
36+
MagicMock(return_value=mock_pki),
37+
),
38+
patch(
39+
"netengine.phases.phase_platform_identity.DockerHandler",
40+
MagicMock(return_value=mock_docker),
41+
),
42+
patch(
43+
"netengine.phases.phase_platform_identity.OIDCHandler",
44+
MagicMock(return_value=mock_oidc),
45+
),
46+
patch(
47+
"netengine.phases.phase_platform_identity.DNSHandler",
48+
MagicMock(return_value=mock_dns),
49+
),
50+
patch("netengine.phases.phase_platform_identity.os"),
51+
patch("netengine.phases.phase_platform_identity.open", mock_open()),
52+
patch.object(PlatformIdentityPhaseHandler, "_wait_for_keycloak", AsyncMock()),
53+
]
54+
55+
for p in patches:
56+
p.start()
57+
58+
yield {
59+
"context": phase_context,
60+
"pki": mock_pki,
61+
"docker": mock_docker,
62+
"oidc": mock_oidc,
63+
"dns": mock_dns,
64+
}
65+
66+
for p in patches:
67+
p.stop()
68+
69+
70+
class TestPlatformIdentityPhaseHandlerExecute:
71+
"""Tests for Phase 4 execute() with mocked external dependencies."""
72+
73+
@pytest.mark.asyncio
74+
async def test_execute_populates_identity_platform_output(self, patched_platform_deps):
75+
"""Phase 4 execute should set identity_platform_output on runtime_state."""
76+
ctx = patched_platform_deps["context"]
77+
await PlatformIdentityPhaseHandler().execute(ctx)
78+
79+
assert ctx.runtime_state.identity_platform_output is not None
80+
81+
@pytest.mark.asyncio
82+
async def test_execute_output_has_required_keys(self, patched_platform_deps):
83+
"""Phase 4 output must include all required identity_platform_output keys."""
84+
ctx = patched_platform_deps["context"]
85+
await PlatformIdentityPhaseHandler().execute(ctx)
86+
87+
output = ctx.runtime_state.identity_platform_output
88+
for key in (
89+
"keycloak_container_id",
90+
"platform_realm_id",
91+
"admin_user_id",
92+
"platform_client_id",
93+
"deployed_at",
94+
):
95+
assert key in output, f"Missing required key '{key}' in identity_platform_output"
96+
97+
@pytest.mark.asyncio
98+
async def test_execute_marks_phase_completed(self, patched_platform_deps):
99+
"""Phase 4 execute should set phase_completed['4'] = True."""
100+
ctx = patched_platform_deps["context"]
101+
await PlatformIdentityPhaseHandler().execute(ctx)
102+
103+
assert ctx.runtime_state.phase_completed.get("4") is True
104+
105+
@pytest.mark.asyncio
106+
async def test_execute_sets_container_id_on_runtime_state(self, patched_platform_deps):
107+
"""Phase 4 should persist the Keycloak container ID to runtime_state."""
108+
ctx = patched_platform_deps["context"]
109+
await PlatformIdentityPhaseHandler().execute(ctx)
110+
111+
assert ctx.runtime_state.keycloak_platform_container_id == "keycloak-ctr-abc"
112+
113+
@pytest.mark.asyncio
114+
async def test_execute_registers_auth_dns_record(self, patched_platform_deps):
115+
"""Phase 4 should register an A record for auth.<zone> pointing to the listen IP."""
116+
ctx = patched_platform_deps["context"]
117+
mock_dns = patched_platform_deps["dns"]
118+
await PlatformIdentityPhaseHandler().execute(ctx)
119+
120+
# spec.identity_platform.listen_ip == "10.0.0.7" in minimal.yaml
121+
mock_dns.add_zone_record.assert_called_once_with(
122+
ctx, "platform.internal", "A", "auth", "10.0.0.7", 300
123+
)
124+
125+
@pytest.mark.asyncio
126+
async def test_execute_generates_bootstrap_admin_password(self, patched_platform_deps):
127+
"""Phase 4 should generate a bootstrap admin password when none exists."""
128+
ctx = patched_platform_deps["context"]
129+
assert ctx.runtime_state.bootstrap_admin_password is None
130+
131+
await PlatformIdentityPhaseHandler().execute(ctx)
132+
133+
assert ctx.runtime_state.bootstrap_admin_password is not None
134+
assert len(ctx.runtime_state.bootstrap_admin_password) > 0
135+
136+
@pytest.mark.asyncio
137+
async def test_execute_reuses_existing_admin_password(self, patched_platform_deps):
138+
"""Phase 4 should not overwrite a bootstrap admin password already in state."""
139+
ctx = patched_platform_deps["context"]
140+
ctx.runtime_state.bootstrap_admin_password = "already-set-password"
141+
142+
await PlatformIdentityPhaseHandler().execute(ctx)
143+
144+
assert ctx.runtime_state.bootstrap_admin_password == "already-set-password"
145+
146+
@pytest.mark.asyncio
147+
async def test_execute_issues_tls_cert_for_auth_hostname(self, patched_platform_deps):
148+
"""Phase 4 should request a TLS cert for auth.platform.internal via PKIHandler."""
149+
ctx = patched_platform_deps["context"]
150+
mock_pki = patched_platform_deps["pki"]
151+
await PlatformIdentityPhaseHandler().execute(ctx)
152+
153+
mock_pki.issue_cert.assert_awaited_once_with("auth.platform.internal", [])
154+
155+
@pytest.mark.asyncio
156+
async def test_execute_creates_platform_realm(self, patched_platform_deps):
157+
"""Phase 4 should create the platform OIDC realm via OIDCHandler."""
158+
ctx = patched_platform_deps["context"]
159+
mock_oidc = patched_platform_deps["oidc"]
160+
await PlatformIdentityPhaseHandler().execute(ctx)
161+
162+
mock_oidc.create_platform_realm.assert_awaited_once_with("platform")
163+
164+
@pytest.mark.asyncio
165+
async def test_execute_persists_realm_and_user_ids(self, patched_platform_deps):
166+
"""Phase 4 should write realm and user IDs to runtime_state."""
167+
ctx = patched_platform_deps["context"]
168+
await PlatformIdentityPhaseHandler().execute(ctx)
169+
170+
assert ctx.runtime_state.platform_realm_id == "platform-realm-id"
171+
assert ctx.runtime_state.admin_user_id == "admin-user-id"
172+
assert ctx.runtime_state.platform_client_id == "platform-api-client-id"

0 commit comments

Comments
 (0)