test: add edge case tests for TLS certificate generation and SSL serve behavior

This commit is contained in:
Brian Krabach
2026-04-03 22:13:39 -07:00
parent fad9c10bbb
commit c2c916077e
2 changed files with 89 additions and 0 deletions
+33
View File
@@ -1634,3 +1634,36 @@ def test_doctor_shows_tls_clipboard_warning(tmp_path, monkeypatch, capsys):
assert "clipboard" in out_lower or "https" in out_lower, ( assert "clipboard" in out_lower or "https" in out_lower, (
f"Expected 'clipboard' or 'https' in doctor TLS-disabled output, got: {out!r}" f"Expected 'clipboard' or 'https' in doctor TLS-disabled output, got: {out!r}"
) )
# ---------------------------------------------------------------------------
# task-7: Edge case tests for serve() TLS behavior
# ---------------------------------------------------------------------------
def test_serve_warns_when_only_cert_set(tmp_path, monkeypatch, capsys):
"""serve() must NOT enable SSL when tls_cert is set but tls_key is empty string."""
import muxplex.cli as cli_mod
# Create a real cert file so tls_cert path check passes the "file exists" guard
cert_file = tmp_path / "server.crt"
cert_file.write_text("fake cert content")
settings_file = tmp_path / "settings.json"
monkeypatch.setattr("muxplex.settings.SETTINGS_PATH", settings_file)
uvicorn_calls = []
def fake_run(*args, **kwargs):
uvicorn_calls.append(kwargs)
with patch("uvicorn.run", fake_run):
with patch.dict("sys.modules", {"muxplex.main": MagicMock()}):
cli_mod.serve(tls_cert=str(cert_file), tls_key="")
assert len(uvicorn_calls) == 1
kwargs = uvicorn_calls[0]
assert "ssl_certfile" not in kwargs, (
"serve() must NOT pass ssl_certfile to uvicorn when tls_key is empty string — "
"SSL requires both cert and key"
)
+56
View File
@@ -156,3 +156,59 @@ def test_get_cert_info_returns_none_for_missing_file(tmp_path):
assert result is None, ( assert result is None, (
f"get_cert_info() must return None for missing file, got: {result!r}" f"get_cert_info() must return None for missing file, got: {result!r}"
) )
# ---------------------------------------------------------------------------
# 1012. Edge case tests
# ---------------------------------------------------------------------------
def test_generate_self_signed_with_custom_hostnames(tmp_path):
"""generate_self_signed() with custom hostnames must include all of them in result['hostnames']."""
from muxplex.tls import generate_self_signed
cert_path = tmp_path / "cert.pem"
key_path = tmp_path / "key.pem"
custom_hostnames = ["mybox.local", "mybox.tailnet.ts.net"]
result = generate_self_signed(cert_path, key_path, hostnames=custom_hostnames)
assert isinstance(result, dict), "generate_self_signed() must return a dict"
assert isinstance(result.get("hostnames"), list), "result['hostnames'] must be a list"
assert "mybox.local" in result["hostnames"], (
f"'mybox.local' must be in result['hostnames'], got: {result['hostnames']!r}"
)
assert "mybox.tailnet.ts.net" in result["hostnames"], (
f"'mybox.tailnet.ts.net' must be in result['hostnames'], got: {result['hostnames']!r}"
)
def test_get_cert_info_hostnames_include_ip(tmp_path):
"""get_cert_info() must include '127.0.0.1' in hostnames (from IP SANs added by generate_self_signed)."""
from muxplex.tls import generate_self_signed, get_cert_info
cert_path = tmp_path / "cert.pem"
key_path = tmp_path / "key.pem"
generate_self_signed(cert_path, key_path, hostnames=["localhost"])
info = get_cert_info(cert_path)
assert info is not None, "get_cert_info() must not return None for a valid cert"
assert "hostnames" in info, "get_cert_info() result must have 'hostnames' key"
assert "127.0.0.1" in info["hostnames"], (
f"'127.0.0.1' must be in info['hostnames'] (IP SANs), got: {info['hostnames']!r}"
)
def test_get_cert_info_returns_none_for_corrupt_file(tmp_path):
"""get_cert_info() must return None for a file containing invalid PEM data."""
from muxplex.tls import get_cert_info
corrupt_pem = tmp_path / "corrupt.pem"
corrupt_pem.write_text("THIS IS NOT A CERTIFICATE")
result = get_cert_info(corrupt_pem)
assert result is None, (
f"get_cert_info() must return None for corrupt PEM file, got: {result!r}"
)