Files
dns-sync/tests/test_orchestrator_authority.py
T

323 lines
7.6 KiB
Python

import unittest
from dataclasses import dataclass, field
from datetime import datetime, timezone
from dns_sync.adapters import (
CERTIFICATES,
DNS_RECORDS,
PROXY_HOSTS,
Capability,
CapabilityOperation,
DiscoveredObject,
Endpoint,
NormalizedObject,
Observation,
)
from dns_sync.orchestrator import discover_reconcile_plan
from dns_sync.persistence import SQLiteStateStore
T1 = datetime(
2026, 9, 20, 8, 0, tzinfo=timezone.utc
)
T2 = datetime(
2026, 9, 20, 9, 0, tzinfo=timezone.utc
)
@dataclass
class FakeAdapter:
endpoint: Endpoint
capabilities: frozenset[Capability]
discovered: dict[str, list[DiscoveredObject]] = field(
default_factory=dict
)
failures: dict[str, str] = field(
default_factory=dict
)
def connect(self) -> None:
return None
def discover(
self,
object_type: str,
) -> list[DiscoveredObject]:
if object_type in self.failures:
raise RuntimeError(
self.failures[object_type]
)
return list(
self.discovered.get(
object_type,
[],
)
)
def capability_set(
*object_types: str,
apply: bool = False,
) -> frozenset[Capability]:
rows = {
Capability(
object_type,
CapabilityOperation.DISCOVER,
)
for object_type in object_types
}
if apply:
rows.update(
Capability(
object_type,
CapabilityOperation.APPLY,
)
for object_type in object_types
)
return frozenset(rows)
def normalized_certificate(
local_key: str,
*,
valid_from: str,
expires_on: str,
) -> NormalizedObject:
return NormalizedObject(
object_type=CERTIFICATES,
logical_key="app.example.com",
local_key=local_key,
payload={
"domain_names": ["app.example.com"],
"provider": "other",
"valid_from": valid_from,
"expires_on": expires_on,
},
)
def discovered_certificate(
local_key: str,
*,
valid_from: str,
expires_on: str,
) -> DiscoveredObject:
return DiscoveredObject(
object_type=CERTIFICATES,
local_key=local_key,
payload={
"domain_names": ["app.example.com"],
"provider": "other",
"valid_from": valid_from,
"expires_on": expires_on,
},
)
def normalized_proxy(
local_key: str,
) -> NormalizedObject:
return NormalizedObject(
object_type=PROXY_HOSTS,
logical_key="app.example.com",
local_key=local_key,
payload={
"domain_names": ["app.example.com"],
"forward_scheme": "http",
"forward_host": "backend.internal",
"forward_port": 8080,
"enabled": True,
},
)
class ObservationAuthorityTests(unittest.TestCase):
def test_failed_newer_certificate_cache_cannot_override_live_certificate(self):
live_endpoint = Endpoint(
"npm",
"192.168.1.3:81",
)
failed_endpoint = Endpoint(
"npm",
"192.168.1.4:81",
)
live = FakeAdapter(
endpoint=live_endpoint,
capabilities=capability_set(
CERTIFICATES,
),
discovered={
CERTIFICATES: [
discovered_certificate(
"20",
valid_from=(
"2026-09-15T00:00:00+00:00"
),
expires_on=(
"2026-12-15T00:00:00+00:00"
),
)
]
},
)
failed = FakeAdapter(
endpoint=failed_endpoint,
capabilities=capability_set(
CERTIFICATES,
apply=True,
),
failures={
CERTIFICATES: "offline"
},
)
cached_newer = normalized_certificate(
"99",
valid_from=(
"2026-09-19T00:00:00+00:00"
),
expires_on=(
"2026-12-19T00:00:00+00:00"
),
)
with SQLiteStateStore(":memory:") as store:
store.replace_observations(
failed_endpoint.identity,
CERTIFICATES,
[
Observation(
failed_endpoint.identity,
cached_newer,
T1,
)
],
T1,
)
result = discover_reconcile_plan(
[
live,
failed,
],
store,
target_ip="192.168.1.101",
run_at=T2,
)
certificates = [
object
for object in result.desired
if object.object_type == CERTIFICATES
]
self.assertEqual(
len(certificates),
1,
)
self.assertEqual(
certificates[0].payload["valid_from"],
"2026-09-15T00:00:00+00:00",
)
# The failed target advertised APPLY, but it must not
# receive a certificate mutation plan this run.
self.assertEqual(
result.plans,
(),
)
self.assertTrue(
any(
observation.endpoint_id
== failed_endpoint.identity
and observation.object.local_key == "99"
for observation in result.observations
)
)
def test_all_failed_sources_preserve_persisted_desired_without_planning(self):
npm_endpoint = Endpoint(
"npm",
"192.168.1.3:81",
)
npm = FakeAdapter(
endpoint=npm_endpoint,
capabilities=capability_set(
PROXY_HOSTS,
apply=True,
),
failures={
PROXY_HOSTS: "offline"
},
)
cached_proxy = normalized_proxy("12")
previous_dns = NormalizedObject(
object_type=DNS_RECORDS,
logical_key="app.example.com",
payload={
"hostname": "app.example.com",
"ip_address": "192.168.1.101",
},
)
with SQLiteStateStore(":memory:") as store:
store.replace_observations(
npm_endpoint.identity,
PROXY_HOSTS,
[
Observation(
npm_endpoint.identity,
cached_proxy,
T1,
)
],
T1,
)
store.replace_desired_state(
DNS_RECORDS,
[previous_dns],
T1,
)
result = discover_reconcile_plan(
[npm],
store,
target_ip="192.168.1.101",
run_at=T2,
)
persisted_dns = store.load_desired_state(
DNS_RECORDS
)
self.assertEqual(
result.desired,
(),
)
self.assertEqual(
result.plans,
(),
)
self.assertEqual(
len(persisted_dns),
1,
)
self.assertEqual(
persisted_dns[0].object,
previous_dns,
)
if __name__ == "__main__":
unittest.main()