Test: cover client-IP/ARP resolution and SAIP schema lookup
Make get_mac_from_arp take an arp_path for testability (default unchanged), and add tests for get_client_ip (X-Forwarded-For vs remote_addr), ARP MAC resolution (match/no-match/missing), SAIP decode-unavailable, and the SAIP_ASN_PATH override. Coverage: utils 100%, overall 93%; 108 tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
c33843d1ec
commit
7b0827499a
|
|
@ -91,10 +91,10 @@ def get_client_ip(request) -> str:
|
||||||
return request.remote_addr or ""
|
return request.remote_addr or ""
|
||||||
|
|
||||||
|
|
||||||
def get_mac_from_arp(ip: str) -> Optional[str]:
|
def get_mac_from_arp(ip: str, arp_path: str = "/proc/net/arp") -> Optional[str]:
|
||||||
"""Attempt to resolve a MAC address from /proc/net/arp for the given IP."""
|
"""Attempt to resolve a MAC address from the ARP table for the given IP."""
|
||||||
try:
|
try:
|
||||||
with open("/proc/net/arp") as f:
|
with open(arp_path) as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
parts = line.split()
|
parts = line.split()
|
||||||
if len(parts) >= 4 and parts[0] == ip:
|
if len(parts) >= 4 and parts[0] == ip:
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,22 @@ class TestSaipEncoding:
|
||||||
saip.create_saip_profile("302720000000001", generate_ki(),
|
saip.create_saip_profile("302720000000001", generate_ki(),
|
||||||
b"\x00" * 16, generate_iccid())
|
b"\x00" * 16, generate_iccid())
|
||||||
|
|
||||||
|
def test_decode_unavailable_raises(self, monkeypatch):
|
||||||
|
monkeypatch.setattr(saip, "_compiler", lambda: None)
|
||||||
|
with pytest.raises(RuntimeError, match="unavailable"):
|
||||||
|
saip.decode_saip_profile(b"\x00")
|
||||||
|
|
||||||
|
def test_find_asn_honours_env_override(self, tmp_path, monkeypatch):
|
||||||
|
fake = tmp_path / "schema.asn"
|
||||||
|
fake.write_text("-- placeholder\n")
|
||||||
|
monkeypatch.setenv("SAIP_ASN_PATH", str(fake))
|
||||||
|
assert saip.find_saip_asn() == str(fake)
|
||||||
|
|
||||||
|
def test_find_asn_ignores_missing_override(self, monkeypatch):
|
||||||
|
monkeypatch.setenv("SAIP_ASN_PATH", "/no/such/schema.asn")
|
||||||
|
# Falls through to the pySim lookup (or None); never returns the bad path.
|
||||||
|
assert saip.find_saip_asn() != "/no/such/schema.asn"
|
||||||
|
|
||||||
@saip_required
|
@saip_required
|
||||||
def test_produces_der_bytes(self):
|
def test_produces_der_bytes(self):
|
||||||
ki = generate_ki()
|
ki = generate_ki()
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ import pytest
|
||||||
|
|
||||||
from server.utils import (
|
from server.utils import (
|
||||||
ensure_parent_dir,
|
ensure_parent_dir,
|
||||||
|
get_client_ip,
|
||||||
|
get_mac_from_arp,
|
||||||
load_config,
|
load_config,
|
||||||
normalize_mac,
|
normalize_mac,
|
||||||
validate_imsi,
|
validate_imsi,
|
||||||
|
|
@ -10,6 +12,41 @@ from server.utils import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class _FakeRequest:
|
||||||
|
def __init__(self, headers=None, remote_addr=None):
|
||||||
|
self.headers = headers or {}
|
||||||
|
self.remote_addr = remote_addr
|
||||||
|
|
||||||
|
|
||||||
|
class TestClientResolution:
|
||||||
|
def test_client_ip_prefers_forwarded(self):
|
||||||
|
req = _FakeRequest(headers={"X-Forwarded-For": "203.0.113.7, 10.0.0.1"},
|
||||||
|
remote_addr="10.0.0.1")
|
||||||
|
assert get_client_ip(req) == "203.0.113.7"
|
||||||
|
|
||||||
|
def test_client_ip_falls_back_to_remote_addr(self):
|
||||||
|
assert get_client_ip(_FakeRequest(remote_addr="192.168.4.10")) == "192.168.4.10"
|
||||||
|
|
||||||
|
def test_client_ip_empty_when_unknown(self):
|
||||||
|
assert get_client_ip(_FakeRequest()) == ""
|
||||||
|
|
||||||
|
def test_mac_from_arp_match(self, tmp_path):
|
||||||
|
arp = tmp_path / "arp"
|
||||||
|
arp.write_text(
|
||||||
|
"IP address HW type Flags HW address Mask Device\n"
|
||||||
|
"192.168.4.10 0x1 0x2 AA:BB:CC:DD:EE:FF * wlan0\n"
|
||||||
|
)
|
||||||
|
assert get_mac_from_arp("192.168.4.10", str(arp)) == "aa:bb:cc:dd:ee:ff"
|
||||||
|
|
||||||
|
def test_mac_from_arp_no_match(self, tmp_path):
|
||||||
|
arp = tmp_path / "arp"
|
||||||
|
arp.write_text("IP address ...\n192.168.4.99 0x1 0x2 11:22:33:44:55:66 * wlan0\n")
|
||||||
|
assert get_mac_from_arp("192.168.4.10", str(arp)) is None
|
||||||
|
|
||||||
|
def test_mac_from_arp_missing_file(self):
|
||||||
|
assert get_mac_from_arp("192.168.4.10", "/no/such/arp") is None
|
||||||
|
|
||||||
|
|
||||||
class TestEnsureParentDir:
|
class TestEnsureParentDir:
|
||||||
def test_bare_filename_does_not_crash(self):
|
def test_bare_filename_does_not_crash(self):
|
||||||
# No directory component -> must be a no-op, not FileNotFoundError.
|
# No directory component -> must be a no-op, not FileNotFoundError.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user