test: raise coverage 68.7% -> ~80.4%; add ~250 tests for new egress/DDNS/network paths
Unit Tests / test (push) Successful in 12m6s

Coverage was below acceptable levels and several newly-added code paths
(sshuttle egress, proxy egress, DDNS provider stubs, DNS overview route,
peer-registry provisioning) had zero test coverage.

~250 new unit tests are added across 16 new test files. Existing test files
are updated to match refactored interfaces (DHCP removed, constants
introduced, network_manager restructured). .coveragerc is added to pin the
source mapping and the 70% floor so regressions are caught at commit time.

tests/test_enhanced_api.py was previously living in api/ (wrong location)
and is moved to tests/ where it belongs.

Integration test files are updated to remove references to DHCP endpoints
and add coverage for the new DNS overview and DDNS sync endpoints.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 09:03:39 -04:00
parent c41cadafb4
commit aa1e5c41ec
33 changed files with 9446 additions and 631 deletions
+4 -4
View File
@@ -90,7 +90,7 @@ class TestConfig:
# ---------------------------------------------------------------------------
EXPECTED_CONTAINERS = [
'cell-caddy', 'cell-dns', 'cell-dhcp', 'cell-ntp',
'cell-caddy', 'cell-dns', 'cell-ntp',
'cell-mail', 'cell-radicale', 'cell-webdav', 'cell-wireguard',
'cell-api', 'cell-webui', 'cell-rainloop', 'cell-filegator',
]
@@ -164,7 +164,7 @@ class TestWireGuard:
# ---------------------------------------------------------------------------
# Network services: DNS, DHCP, NTP
# Network services: DNS, NTP
# ---------------------------------------------------------------------------
class TestNetworkServices:
@@ -176,8 +176,8 @@ class TestNetworkServices:
r = get('/api/dns/status')
assert r.status_code == 200
def test_dhcp_leases_endpoint(self):
r = get('/api/dhcp/leases')
def test_dns_overview_endpoint(self):
r = get('/api/dns/overview')
assert r.status_code == 200
def test_ntp_status_endpoint(self):
@@ -11,7 +11,6 @@ Endpoints covered:
- /api/peers (POST, PUT, DELETE)
- /api/config (PUT)
- /api/dns/records (DELETE)
- /api/dhcp/reservations (POST, DELETE)
- /api/containers/<name>/restart
- /api/wireguard/keys/peer
@@ -240,43 +239,6 @@ class TestDnsRecordsNegative:
r.json()
# ---------------------------------------------------------------------------
# DHCP reservations — negative
# ---------------------------------------------------------------------------
class TestDhcpReservationsNegative:
def test_add_reservation_no_body_returns_400(self):
r = _S.post(
f"{API_BASE}/api/dhcp/reservations",
data='',
headers={'Content-Type': 'application/json'},
)
assert r.status_code == 400
def test_add_reservation_missing_ip_returns_400(self):
r = post('/api/dhcp/reservations', json={'mac': 'aa:bb:cc:dd:ee:ff'})
assert r.status_code == 400
_assert_json_error(r)
def test_add_reservation_missing_mac_returns_400(self):
r = post('/api/dhcp/reservations', json={'ip': '10.0.0.250'})
assert r.status_code == 400
_assert_json_error(r)
def test_delete_reservation_no_mac_returns_400(self):
r = delete('/api/dhcp/reservations', json={'ip': '10.0.0.250'})
assert r.status_code == 400
_assert_json_error(r)
def test_delete_reservation_empty_body_returns_400(self):
r = _S.delete(
f"{API_BASE}/api/dhcp/reservations",
data='',
headers={'Content-Type': 'application/json'},
)
assert r.status_code == 400
# ---------------------------------------------------------------------------
# Container endpoints — negative
# ---------------------------------------------------------------------------
+12 -73
View File
@@ -1,10 +1,8 @@
"""
Network services integration tests: DNS records, DHCP leases, DHCP reservations.
Network services integration tests: DNS records, DNS overview.
Note on endpoint shapes discovered from app.py:
- DELETE /api/dns/records takes a JSON body (not a URL param)
- DELETE /api/dhcp/reservations takes JSON body with 'mac' field
- POST /api/dhcp/reservations requires 'mac' and 'ip' fields
- DELETE /api/dns/records takes a JSON body (not a URL param)
Run with: pytest tests/integration/test_network_services.py -v
"""
@@ -129,79 +127,20 @@ class TestDnsRecordsWrite:
# ---------------------------------------------------------------------------
# GET /api/dhcp/leases
# GET /api/dns/overview
# ---------------------------------------------------------------------------
class TestDhcpLeases:
def test_get_dhcp_leases_returns_200(self):
r = get('/api/dhcp/leases')
class TestDnsOverview:
def test_get_dns_overview_returns_200(self):
r = get('/api/dns/overview')
assert r.status_code == 200
def test_get_dhcp_leases_returns_list_or_dict(self):
data = get('/api/dhcp/leases').json()
assert isinstance(data, (list, dict))
# ---------------------------------------------------------------------------
# POST /api/dhcp/reservations + DELETE /api/dhcp/reservations
# ---------------------------------------------------------------------------
_TEST_MAC = 'de:ad:be:ef:11:22'
_TEST_RESERVATION_IP = '10.0.0.200'
class TestDhcpReservations:
def _cleanup(self):
delete('/api/dhcp/reservations', json={'mac': _TEST_MAC})
def test_add_dhcp_reservation_returns_non_error(self):
try:
r = post('/api/dhcp/reservations', json={
'mac': _TEST_MAC,
'ip': _TEST_RESERVATION_IP,
'hostname': 'inttest-dhcp-host',
})
assert r.status_code in (200, 201), (
f"Expected 200/201 for DHCP reservation, got {r.status_code}: {r.text}"
)
finally:
self._cleanup()
def test_add_dhcp_reservation_missing_mac_returns_400(self):
r = post('/api/dhcp/reservations', json={'ip': _TEST_RESERVATION_IP})
assert r.status_code == 400
assert 'error' in r.json()
def test_add_dhcp_reservation_missing_ip_returns_400(self):
r = post('/api/dhcp/reservations', json={'mac': _TEST_MAC})
assert r.status_code == 400
assert 'error' in r.json()
def test_add_dhcp_reservation_empty_body_returns_400(self):
r = post('/api/dhcp/reservations', data='')
assert r.status_code == 400
def test_delete_dhcp_reservation_missing_mac_returns_400(self):
r = delete('/api/dhcp/reservations', json={})
assert r.status_code == 400
assert 'error' in r.json()
def test_add_and_delete_dhcp_reservation_round_trip(self):
add_r = post('/api/dhcp/reservations', json={
'mac': _TEST_MAC,
'ip': _TEST_RESERVATION_IP,
})
assert add_r.status_code in (200, 201), (
f"Could not create DHCP reservation: {add_r.text}"
)
try:
del_r = delete('/api/dhcp/reservations', json={'mac': _TEST_MAC})
assert del_r.status_code in (200, 204), (
f"DHCP reservation delete failed: {del_r.status_code} {del_r.text}"
)
except Exception:
self._cleanup()
raise
def test_get_dns_overview_has_expected_keys(self):
data = get('/api/dns/overview').json()
assert isinstance(data, dict)
for key in ('mode', 'effective_domain', 'internal_domain',
'public_records', 'internal_records'):
assert key in data
# ---------------------------------------------------------------------------