- Added main.py: automatic WireGuard MTU calculation and PMTU probing - Added test.py: unittests covering base, PMTU, and fallback scenarios - Added Makefile: includes test target and install guidance - Added README.md: usage, pkgmgr installation, and MIT license Reference: https://chatgpt.com/share/68efc179-1a10-800f-9656-1e8731b40546
135 lines
5.0 KiB
Python
135 lines
5.0 KiB
Python
import io
|
|
import sys
|
|
import unittest
|
|
from unittest.mock import patch, call
|
|
from contextlib import redirect_stdout
|
|
|
|
# Import the script as a module
|
|
import main as automtu
|
|
|
|
|
|
class TestWgMtuAuto(unittest.TestCase):
|
|
|
|
@patch("main.set_mtu")
|
|
@patch("main.read_mtu", return_value=1500)
|
|
@patch("main.exists_iface", return_value=True)
|
|
@patch("main.get_default_ifaces", return_value=["eth0"])
|
|
@patch("main.require_root", return_value=None)
|
|
def test_no_pmtu_uses_egress_minus_overhead(
|
|
self, _req_root, _get_def, _exists, _read_mtu, mock_set_mtu
|
|
):
|
|
"""
|
|
Without PMTU probing, wg MTU should be base_mtu - overhead (clamped by min).
|
|
With base=1500, overhead=80 ⇒ wg_mtu=1420.
|
|
"""
|
|
argv = ["main.py", "--dry-run"]
|
|
with patch.object(sys, "argv", argv):
|
|
buf = io.StringIO()
|
|
with redirect_stdout(buf):
|
|
automtu.main()
|
|
|
|
out = buf.getvalue()
|
|
self.assertIn("Detected egress interface: eth0", out)
|
|
self.assertIn("Egress base MTU: 1500", out)
|
|
self.assertIn("Computed wg0 MTU: 1420", out)
|
|
|
|
# dry-run still calls set_mtu (but prints DRY-RUN); ensure it targeted wg0 with 1420
|
|
mock_set_mtu.assert_any_call("wg0", 1420, True)
|
|
|
|
@patch("main.set_mtu")
|
|
@patch("main.exists_iface", return_value=True)
|
|
@patch("main.get_default_ifaces", return_value=["eth0"])
|
|
@patch("main.require_root", return_value=None)
|
|
def test_force_egress_mtu_and_pmtu_multiple_targets_min_policy(
|
|
self, _req_root, _get_def, _exists, mock_set_mtu
|
|
):
|
|
"""
|
|
base_mtu forced=1452; PMTU results: 1452, 1420 -> policy=min => 1420 chosen.
|
|
effective=min(1452,1420)=1420; wg_mtu=1420-80=1340
|
|
"""
|
|
with patch("main.read_mtu", return_value=9999): # should be ignored because we force
|
|
with patch("main.probe_pmtu", side_effect=[1452, 1420]):
|
|
argv = [
|
|
"main.py",
|
|
"--dry-run",
|
|
"--force-egress-mtu", "1452",
|
|
"--pmtu-target", "t1",
|
|
"--pmtu-target", "t2",
|
|
"--pmtu-policy", "min",
|
|
]
|
|
with patch.object(sys, "argv", argv):
|
|
buf = io.StringIO()
|
|
with redirect_stdout(buf):
|
|
automtu.main()
|
|
|
|
out = buf.getvalue()
|
|
self.assertIn("Forcing egress MTU 1452 on eth0", out)
|
|
self.assertIn("Probing Path MTU for: t1, t2 (policy=min)", out)
|
|
self.assertIn("Selected Path MTU (policy=min): 1420", out)
|
|
self.assertIn("Computed wg0 MTU: 1340", out)
|
|
mock_set_mtu.assert_any_call("wg0", 1340, True)
|
|
|
|
@patch("main.set_mtu")
|
|
@patch("main.read_mtu", return_value=1500)
|
|
@patch("main.exists_iface", return_value=True)
|
|
@patch("main.get_default_ifaces", return_value=["eth0"])
|
|
@patch("main.require_root", return_value=None)
|
|
def test_pmtu_policy_median(
|
|
self, _req_root, _get_def, _exists, _read_mtu, mock_set_mtu
|
|
):
|
|
"""
|
|
base=1500; PMTUs: 1500, 1452, 1472 -> median=1472.
|
|
effective=min(1500,1472)=1472; wg_mtu=1472-80=1392
|
|
"""
|
|
with patch("main.probe_pmtu", side_effect=[1500, 1452, 1472]):
|
|
argv = [
|
|
"main.py",
|
|
"--dry-run",
|
|
"--pmtu-target", "a",
|
|
"--pmtu-target", "b",
|
|
"--pmtu-target", "c",
|
|
"--pmtu-policy", "median",
|
|
]
|
|
with patch.object(sys, "argv", argv):
|
|
buf = io.StringIO()
|
|
with redirect_stdout(buf):
|
|
automtu.main()
|
|
|
|
out = buf.getvalue()
|
|
self.assertIn("Probing Path MTU for: a, b, c (policy=median)", out)
|
|
self.assertIn("Selected Path MTU (policy=median): 1472", out)
|
|
self.assertIn("Computed wg0 MTU: 1392", out)
|
|
mock_set_mtu.assert_any_call("wg0", 1392, True)
|
|
|
|
@patch("main.set_mtu")
|
|
@patch("main.read_mtu", return_value=1500)
|
|
@patch("main.exists_iface", return_value=True)
|
|
@patch("main.get_default_ifaces", return_value=["eth0"])
|
|
@patch("main.require_root", return_value=None)
|
|
def test_pmtu_all_fail_falls_back_to_base(
|
|
self, _req_root, _get_def, _exists, _read_mtu, mock_set_mtu
|
|
):
|
|
"""
|
|
If all PMTU probes fail, fall back to base MTU (1500) => wg_mtu=1420.
|
|
"""
|
|
with patch("main.probe_pmtu", side_effect=[None, None]):
|
|
argv = [
|
|
"main.py",
|
|
"--dry-run",
|
|
"--pmtu-target", "bad1",
|
|
"--pmtu-target", "bad2",
|
|
]
|
|
with patch.object(sys, "argv", argv):
|
|
buf = io.StringIO()
|
|
with redirect_stdout(buf):
|
|
automtu.main()
|
|
|
|
out = buf.getvalue()
|
|
self.assertIn("WARNING: All PMTU probes failed. Falling back to egress MTU.", out)
|
|
self.assertIn("Computed wg0 MTU: 1420", out)
|
|
mock_set_mtu.assert_any_call("wg0", 1420, True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|