test: update and add tests for all updated subsystems
This commit is contained in:
+98
-83
@@ -1,3 +1,5 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
@@ -5,93 +7,106 @@ import pytest
|
||||
|
||||
@pytest.fixture
|
||||
def client():
|
||||
from webui.server import app
|
||||
|
||||
app.config["TESTING"] = True
|
||||
return app.test_client()
|
||||
|
||||
|
||||
class TestTemplateFilters:
|
||||
@pytest.fixture
|
||||
def env(self):
|
||||
with patch("lib.logging.setup_logging"):
|
||||
from webui.server import app
|
||||
|
||||
return app.jinja_env
|
||||
|
||||
def test_timestamp_filter_valid(self, env):
|
||||
result = env.filters["timestamp"]("2026-04-01T12:00:00Z")
|
||||
assert "2026-04-01" in result
|
||||
|
||||
def test_timestamp_filter_empty(self, env):
|
||||
assert env.filters["timestamp"]("") == ""
|
||||
assert env.filters["timestamp"](None) == ""
|
||||
|
||||
def test_timestamp_filter_invalid(self, env):
|
||||
result = env.filters["timestamp"]("not-a-date")
|
||||
assert result == "not-a-date"
|
||||
|
||||
def test_bytes_filter_zero(self, env):
|
||||
assert env.filters["bytes"](0) == "0.0 B"
|
||||
|
||||
def test_bytes_filter_kb(self, env):
|
||||
result = env.filters["bytes"](1536)
|
||||
assert "KB" in result
|
||||
|
||||
def test_bytes_filter_mb(self, env):
|
||||
result = env.filters["bytes"](1500000)
|
||||
assert "MB" in result
|
||||
|
||||
def test_bytes_filter_negative(self, env):
|
||||
assert env.filters["bytes"](-1) == "0 B"
|
||||
|
||||
def test_bytes_filter_invalid(self, env):
|
||||
assert env.filters["bytes"]("not-a-number") == "not-a-number"
|
||||
|
||||
def test_duration_filter_zero(self, env):
|
||||
assert env.filters["duration"](0) == "0s"
|
||||
|
||||
def test_duration_filter_seconds(self, env):
|
||||
assert env.filters["duration"](65) == "1m 5s"
|
||||
|
||||
def test_duration_filter_hours(self, env):
|
||||
result = env.filters["duration"](3661)
|
||||
assert "1h" in result
|
||||
|
||||
def test_duration_filter_days(self, env):
|
||||
result = env.filters["duration"](90000)
|
||||
assert "1d" in result
|
||||
|
||||
def test_duration_filter_invalid(self, env):
|
||||
assert env.filters["duration"]("bad") == "bad"
|
||||
|
||||
def test_json_pretty_filter(self, env):
|
||||
result = env.filters["json_pretty"]({"key": "value"})
|
||||
assert '{"key": "value"}' in result or "key" in result
|
||||
app.config["TESTING"] = True
|
||||
return app.test_client()
|
||||
|
||||
|
||||
class TestSafelyHelper:
|
||||
def test_returns_result(self):
|
||||
from webui.server import _safely
|
||||
class TestSPARoutes:
|
||||
def test_root_serves_index(self, client):
|
||||
resp = client.get("/")
|
||||
assert resp.status_code == 200
|
||||
assert b'id="app"' in resp.data
|
||||
|
||||
result = _safely(lambda: 42)
|
||||
assert result == 42
|
||||
|
||||
def test_returns_default_on_exception(self):
|
||||
from webui.server import _safely
|
||||
|
||||
result = _safely(lambda: 1 / 0, default=None)
|
||||
assert result is None
|
||||
|
||||
def test_returns_custom_default(self):
|
||||
from webui.server import _safely
|
||||
|
||||
result = _safely(lambda: 1 / 0, default="fallback")
|
||||
assert result == "fallback"
|
||||
|
||||
|
||||
class TestPageRoutes:
|
||||
@patch("webui.server.get")
|
||||
def test_dashboard_no_crash(self, mock_get, client):
|
||||
mock_get.return_value = {}
|
||||
def test_spa_catch_all_serves_index(self, client):
|
||||
resp = client.get("/dashboard")
|
||||
assert resp.status_code == 200
|
||||
assert b"index.html" in resp.data or b'id="app"' in resp.data
|
||||
|
||||
def test_spa_catch_all_other_page(self, client):
|
||||
resp = client.get("/zones")
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_api_routes_still_work(self, client):
|
||||
resp = client.get("/api/firewall/zones")
|
||||
assert resp.status_code in (200, 502, 503)
|
||||
|
||||
|
||||
class TestWsUrlGeneration:
|
||||
def test_ws_url_ipv4_host(self, client):
|
||||
resp = client.get("/", headers={"Host": "192.168.1.1:9090"})
|
||||
assert b"ws://192.168.1.1:9090/ws" in resp.data
|
||||
|
||||
def test_ws_url_ipv6_host(self, client):
|
||||
resp = client.get("/", headers={"Host": "[::1]:9090"})
|
||||
assert b"ws://[::1]:9090/ws" in resp.data
|
||||
|
||||
|
||||
class TestApiStatusAll:
|
||||
@patch("webui.server.get")
|
||||
def test_success(self, mock_get, client):
|
||||
mock_get.return_value = {"firewall": {"zones": {}}, "dnsmasq": {}}
|
||||
resp = client.get("/api/status/all")
|
||||
assert resp.status_code == 200
|
||||
data = resp.get_json()
|
||||
assert data["ok"] is True
|
||||
assert "firewall" in data["data"]
|
||||
|
||||
@patch("webui.server.get")
|
||||
def test_error(self, mock_get, client):
|
||||
mock_get.side_effect = RuntimeError("connection refused")
|
||||
resp = client.get("/api/status/all")
|
||||
assert resp.status_code == 500
|
||||
data = resp.get_json()
|
||||
assert data["ok"] is False
|
||||
|
||||
|
||||
class TestBlueprintsRegistered:
|
||||
def test_all_blueprints_registered(self, client):
|
||||
from webui.server import BLUEPRINTS
|
||||
|
||||
assert len(BLUEPRINTS) == 7
|
||||
names = [name for name, _ in BLUEPRINTS]
|
||||
assert "firewall" in names
|
||||
assert "network" in names
|
||||
assert "dhcp" in names
|
||||
assert "proxy" in names
|
||||
assert "certs" in names
|
||||
assert "wireguard" in names
|
||||
assert "logs" in names
|
||||
|
||||
|
||||
class TestGroupWriteHandler:
|
||||
def test_creates_file_with_group_write(self, tmp_path: Path) -> None:
|
||||
"""GroupWriteHandler creates new log files with group-write (0o664)."""
|
||||
import contextlib
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
||||
log_file = tmp_path / "test.log"
|
||||
old = os.umask(0o022)
|
||||
try:
|
||||
|
||||
class GroupWriteHandler(RotatingFileHandler):
|
||||
def _open(self):
|
||||
with contextlib.suppress(OSError):
|
||||
os.chmod(self.baseFilename, 0o664)
|
||||
saved = os.umask(0o002)
|
||||
try:
|
||||
fd = os.open(
|
||||
self.baseFilename,
|
||||
os.O_WRONLY | os.O_CREAT | os.O_APPEND,
|
||||
0o664,
|
||||
)
|
||||
finally:
|
||||
os.umask(saved)
|
||||
return os.fdopen(fd, "a", errors="backslashreplace")
|
||||
|
||||
fh = GroupWriteHandler(str(log_file))
|
||||
fh.close()
|
||||
finally:
|
||||
os.umask(old)
|
||||
|
||||
mode = os.stat(log_file).st_mode & 0o777
|
||||
assert mode == 0o664, f"Expected 0o664, got {oct(mode)}"
|
||||
|
||||
Reference in New Issue
Block a user