Stage 7: configuration view — backend service, routers, tests, and frontend
- config_service.py: read/write jail config via asyncio.gather, global settings, in-process regex validation, log preview via _read_tail_lines - server_service.py: read/write server settings, flush logs - config router: 9 endpoints for jail/global config, regex-test, logpath management, log preview - server router: GET/PUT settings, POST flush-logs - models/config.py expanded with JailConfig, GlobalConfigUpdate, LogPreview* models - 285 tests pass (68 new), ruff clean, mypy clean (44 files) - Frontend: types/config.ts, api/config.ts, hooks/useConfig.ts, ConfigPage.tsx full implementation (Jails accordion editor, Global config, Server settings, Regex Tester with preview) - Fixed pre-existing frontend lint: JSX.Element → React.JSX.Element (10 files), void/promise patterns in useServerStatus + useJails, no-misused-spread in client.ts, eslint.config.ts self-excluded
This commit is contained in:
@@ -181,9 +181,8 @@ class TestListJails:
|
||||
def __init__(self, **_kw: Any) -> None:
|
||||
self.send = AsyncMock(side_effect=Fail2BanConnectionError("no socket", _SOCKET))
|
||||
|
||||
with patch("app.services.jail_service.Fail2BanClient", _FailClient):
|
||||
with pytest.raises(Fail2BanConnectionError):
|
||||
await jail_service.list_jails(_SOCKET)
|
||||
with patch("app.services.jail_service.Fail2BanClient", _FailClient), pytest.raises(Fail2BanConnectionError):
|
||||
await jail_service.list_jails(_SOCKET)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -251,9 +250,8 @@ class TestGetJail:
|
||||
"""get_jail raises JailNotFoundError when jail is unknown."""
|
||||
not_found_response = (1, Exception("Unknown jail: 'ghost'"))
|
||||
|
||||
with _patch_client({r"status|ghost|short": not_found_response}):
|
||||
with pytest.raises(JailNotFoundError):
|
||||
await jail_service.get_jail(_SOCKET, "ghost")
|
||||
with _patch_client({r"status|ghost|short": not_found_response}), pytest.raises(JailNotFoundError):
|
||||
await jail_service.get_jail(_SOCKET, "ghost")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -296,15 +294,13 @@ class TestJailControls:
|
||||
|
||||
async def test_start_not_found_raises(self) -> None:
|
||||
"""start_jail raises JailNotFoundError for unknown jail."""
|
||||
with _patch_client({"start|ghost": (1, Exception("Unknown jail: 'ghost'"))}):
|
||||
with pytest.raises(JailNotFoundError):
|
||||
await jail_service.start_jail(_SOCKET, "ghost")
|
||||
with _patch_client({"start|ghost": (1, Exception("Unknown jail: 'ghost'"))}), pytest.raises(JailNotFoundError):
|
||||
await jail_service.start_jail(_SOCKET, "ghost")
|
||||
|
||||
async def test_stop_operation_error_raises(self) -> None:
|
||||
"""stop_jail raises JailOperationError on fail2ban error code."""
|
||||
with _patch_client({"stop|sshd": (1, Exception("cannot stop"))}):
|
||||
with pytest.raises(JailOperationError):
|
||||
await jail_service.stop_jail(_SOCKET, "sshd")
|
||||
with _patch_client({"stop|sshd": (1, Exception("cannot stop"))}), pytest.raises(JailOperationError):
|
||||
await jail_service.stop_jail(_SOCKET, "sshd")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user