Fix backend tests by using per-test temp config dir, align router mocks to service modules, fix log tail helper reference, and add JailNotFoundError.name

This commit is contained in:
2026-03-21 19:43:59 +01:00
parent 1f4ee360f6
commit 2022bcde99
5 changed files with 118 additions and 108 deletions

View File

@@ -6,6 +6,10 @@ from __future__ import annotations
class JailNotFoundError(Exception):
"""Raised when a requested jail name does not exist."""
def __init__(self, name: str) -> None:
self.name = name
super().__init__(f"Jail not found: {name!r}")
class JailOperationError(Exception):
"""Raised when a fail2ban jail operation fails."""

View File

@@ -719,7 +719,7 @@ async def read_fail2ban_log(
total_lines, raw_lines = await asyncio.gather(
loop.run_in_executor(None, _count_file_lines, resolved_str),
loop.run_in_executor(None, _read_tail_lines, resolved_str, lines),
loop.run_in_executor(None, log_service._read_tail_lines, resolved_str, lines),
)
filtered = (

View File

@@ -37,9 +37,15 @@ def test_settings(tmp_path: Path) -> Settings:
Returns:
A :class:`~app.config.Settings` instance with overridden paths.
"""
config_dir = tmp_path / "fail2ban"
(config_dir / "jail.d").mkdir(parents=True)
(config_dir / "filter.d").mkdir(parents=True)
(config_dir / "action.d").mkdir(parents=True)
return Settings(
database_path=str(tmp_path / "test_bangui.db"),
fail2ban_socket="/tmp/fake_fail2ban.sock",
fail2ban_config_dir=str(config_dir),
session_secret="test-secret-key-do-not-use-in-production",
session_duration_minutes=60,
timezone="UTC",

View File

@@ -725,7 +725,7 @@ class TestGetInactiveJails:
mock_response = InactiveJailListResponse(jails=[mock_jail], total=1)
with patch(
"app.routers.config.config_file_service.list_inactive_jails",
"app.routers.config.jail_config_service.list_inactive_jails",
AsyncMock(return_value=mock_response),
):
resp = await config_client.get("/api/config/jails/inactive")
@@ -740,7 +740,7 @@ class TestGetInactiveJails:
from app.models.config import InactiveJailListResponse
with patch(
"app.routers.config.config_file_service.list_inactive_jails",
"app.routers.config.jail_config_service.list_inactive_jails",
AsyncMock(return_value=InactiveJailListResponse(jails=[], total=0)),
):
resp = await config_client.get("/api/config/jails/inactive")
@@ -776,7 +776,7 @@ class TestActivateJail:
message="Jail 'apache-auth' activated successfully.",
)
with patch(
"app.routers.config.config_file_service.activate_jail",
"app.routers.config.jail_config_service.activate_jail",
AsyncMock(return_value=mock_response),
):
resp = await config_client.post(
@@ -796,7 +796,7 @@ class TestActivateJail:
name="apache-auth", active=True, message="Activated."
)
with patch(
"app.routers.config.config_file_service.activate_jail",
"app.routers.config.jail_config_service.activate_jail",
AsyncMock(return_value=mock_response),
) as mock_activate:
resp = await config_client.post(
@@ -812,10 +812,10 @@ class TestActivateJail:
async def test_404_for_unknown_jail(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/missing/activate returns 404."""
from app.services.config_file_service import JailNotFoundInConfigError
from app.services.jail_config_service import JailNotFoundInConfigError
with patch(
"app.routers.config.config_file_service.activate_jail",
"app.routers.config.jail_config_service.activate_jail",
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
):
resp = await config_client.post(
@@ -826,10 +826,10 @@ class TestActivateJail:
async def test_409_when_already_active(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/sshd/activate returns 409 if already active."""
from app.services.config_file_service import JailAlreadyActiveError
from app.services.jail_config_service import JailAlreadyActiveError
with patch(
"app.routers.config.config_file_service.activate_jail",
"app.routers.config.jail_config_service.activate_jail",
AsyncMock(side_effect=JailAlreadyActiveError("sshd")),
):
resp = await config_client.post(
@@ -840,10 +840,10 @@ class TestActivateJail:
async def test_400_for_invalid_jail_name(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/ with bad name returns 400."""
from app.services.config_file_service import JailNameError
from app.services.jail_config_service import JailNameError
with patch(
"app.routers.config.config_file_service.activate_jail",
"app.routers.config.jail_config_service.activate_jail",
AsyncMock(side_effect=JailNameError("bad name")),
):
resp = await config_client.post(
@@ -872,7 +872,7 @@ class TestActivateJail:
message="Jail 'airsonic-auth' cannot be activated: log file '/var/log/airsonic/airsonic.log' not found",
)
with patch(
"app.routers.config.config_file_service.activate_jail",
"app.routers.config.jail_config_service.activate_jail",
AsyncMock(return_value=blocked_response),
):
resp = await config_client.post(
@@ -905,7 +905,7 @@ class TestDeactivateJail:
message="Jail 'sshd' deactivated successfully.",
)
with patch(
"app.routers.config.config_file_service.deactivate_jail",
"app.routers.config.jail_config_service.deactivate_jail",
AsyncMock(return_value=mock_response),
):
resp = await config_client.post("/api/config/jails/sshd/deactivate")
@@ -917,10 +917,10 @@ class TestDeactivateJail:
async def test_404_for_unknown_jail(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/missing/deactivate returns 404."""
from app.services.config_file_service import JailNotFoundInConfigError
from app.services.jail_config_service import JailNotFoundInConfigError
with patch(
"app.routers.config.config_file_service.deactivate_jail",
"app.routers.config.jail_config_service.deactivate_jail",
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
):
resp = await config_client.post(
@@ -931,10 +931,10 @@ class TestDeactivateJail:
async def test_409_when_already_inactive(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/apache-auth/deactivate returns 409 if already inactive."""
from app.services.config_file_service import JailAlreadyInactiveError
from app.services.jail_config_service import JailAlreadyInactiveError
with patch(
"app.routers.config.config_file_service.deactivate_jail",
"app.routers.config.jail_config_service.deactivate_jail",
AsyncMock(side_effect=JailAlreadyInactiveError("apache-auth")),
):
resp = await config_client.post(
@@ -945,10 +945,10 @@ class TestDeactivateJail:
async def test_400_for_invalid_jail_name(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/.../deactivate with bad name returns 400."""
from app.services.config_file_service import JailNameError
from app.services.jail_config_service import JailNameError
with patch(
"app.routers.config.config_file_service.deactivate_jail",
"app.routers.config.jail_config_service.deactivate_jail",
AsyncMock(side_effect=JailNameError("bad")),
):
resp = await config_client.post(
@@ -976,7 +976,7 @@ class TestDeactivateJail:
)
with (
patch(
"app.routers.config.config_file_service.deactivate_jail",
"app.routers.config.jail_config_service.deactivate_jail",
AsyncMock(return_value=mock_response),
),
patch(
@@ -1027,7 +1027,7 @@ class TestListFilters:
total=1,
)
with patch(
"app.routers.config.config_file_service.list_filters",
"app.routers.config.filter_config_service.list_filters",
AsyncMock(return_value=mock_response),
):
resp = await config_client.get("/api/config/filters")
@@ -1043,7 +1043,7 @@ class TestListFilters:
from app.models.config import FilterListResponse
with patch(
"app.routers.config.config_file_service.list_filters",
"app.routers.config.filter_config_service.list_filters",
AsyncMock(return_value=FilterListResponse(filters=[], total=0)),
):
resp = await config_client.get("/api/config/filters")
@@ -1066,7 +1066,7 @@ class TestListFilters:
total=2,
)
with patch(
"app.routers.config.config_file_service.list_filters",
"app.routers.config.filter_config_service.list_filters",
AsyncMock(return_value=mock_response),
):
resp = await config_client.get("/api/config/filters")
@@ -1095,7 +1095,7 @@ class TestGetFilter:
async def test_200_returns_filter(self, config_client: AsyncClient) -> None:
"""GET /api/config/filters/sshd returns 200 with FilterConfig."""
with patch(
"app.routers.config.config_file_service.get_filter",
"app.routers.config.filter_config_service.get_filter",
AsyncMock(return_value=_make_filter_config("sshd")),
):
resp = await config_client.get("/api/config/filters/sshd")
@@ -1108,10 +1108,10 @@ class TestGetFilter:
async def test_404_for_unknown_filter(self, config_client: AsyncClient) -> None:
"""GET /api/config/filters/missing returns 404."""
from app.services.config_file_service import FilterNotFoundError
from app.services.filter_config_service import FilterNotFoundError
with patch(
"app.routers.config.config_file_service.get_filter",
"app.routers.config.filter_config_service.get_filter",
AsyncMock(side_effect=FilterNotFoundError("missing")),
):
resp = await config_client.get("/api/config/filters/missing")
@@ -1138,7 +1138,7 @@ class TestUpdateFilter:
async def test_200_returns_updated_filter(self, config_client: AsyncClient) -> None:
"""PUT /api/config/filters/sshd returns 200 with updated FilterConfig."""
with patch(
"app.routers.config.config_file_service.update_filter",
"app.routers.config.filter_config_service.update_filter",
AsyncMock(return_value=_make_filter_config("sshd")),
):
resp = await config_client.put(
@@ -1151,10 +1151,10 @@ class TestUpdateFilter:
async def test_404_for_unknown_filter(self, config_client: AsyncClient) -> None:
"""PUT /api/config/filters/missing returns 404."""
from app.services.config_file_service import FilterNotFoundError
from app.services.filter_config_service import FilterNotFoundError
with patch(
"app.routers.config.config_file_service.update_filter",
"app.routers.config.filter_config_service.update_filter",
AsyncMock(side_effect=FilterNotFoundError("missing")),
):
resp = await config_client.put(
@@ -1166,10 +1166,10 @@ class TestUpdateFilter:
async def test_422_for_invalid_regex(self, config_client: AsyncClient) -> None:
"""PUT /api/config/filters/sshd returns 422 for bad regex."""
from app.services.config_file_service import FilterInvalidRegexError
from app.services.filter_config_service import FilterInvalidRegexError
with patch(
"app.routers.config.config_file_service.update_filter",
"app.routers.config.filter_config_service.update_filter",
AsyncMock(side_effect=FilterInvalidRegexError("[bad", "unterminated")),
):
resp = await config_client.put(
@@ -1181,10 +1181,10 @@ class TestUpdateFilter:
async def test_400_for_invalid_name(self, config_client: AsyncClient) -> None:
"""PUT /api/config/filters/... with bad name returns 400."""
from app.services.config_file_service import FilterNameError
from app.services.filter_config_service import FilterNameError
with patch(
"app.routers.config.config_file_service.update_filter",
"app.routers.config.filter_config_service.update_filter",
AsyncMock(side_effect=FilterNameError("bad")),
):
resp = await config_client.put(
@@ -1197,7 +1197,7 @@ class TestUpdateFilter:
async def test_reload_query_param_passed(self, config_client: AsyncClient) -> None:
"""PUT /api/config/filters/sshd?reload=true passes do_reload=True."""
with patch(
"app.routers.config.config_file_service.update_filter",
"app.routers.config.filter_config_service.update_filter",
AsyncMock(return_value=_make_filter_config("sshd")),
) as mock_update:
resp = await config_client.put(
@@ -1228,7 +1228,7 @@ class TestCreateFilter:
async def test_201_creates_filter(self, config_client: AsyncClient) -> None:
"""POST /api/config/filters returns 201 with FilterConfig."""
with patch(
"app.routers.config.config_file_service.create_filter",
"app.routers.config.filter_config_service.create_filter",
AsyncMock(return_value=_make_filter_config("my-custom")),
):
resp = await config_client.post(
@@ -1241,10 +1241,10 @@ class TestCreateFilter:
async def test_409_when_already_exists(self, config_client: AsyncClient) -> None:
"""POST /api/config/filters returns 409 if filter exists."""
from app.services.config_file_service import FilterAlreadyExistsError
from app.services.filter_config_service import FilterAlreadyExistsError
with patch(
"app.routers.config.config_file_service.create_filter",
"app.routers.config.filter_config_service.create_filter",
AsyncMock(side_effect=FilterAlreadyExistsError("sshd")),
):
resp = await config_client.post(
@@ -1256,10 +1256,10 @@ class TestCreateFilter:
async def test_422_for_invalid_regex(self, config_client: AsyncClient) -> None:
"""POST /api/config/filters returns 422 for bad regex."""
from app.services.config_file_service import FilterInvalidRegexError
from app.services.filter_config_service import FilterInvalidRegexError
with patch(
"app.routers.config.config_file_service.create_filter",
"app.routers.config.filter_config_service.create_filter",
AsyncMock(side_effect=FilterInvalidRegexError("[bad", "unterminated")),
):
resp = await config_client.post(
@@ -1271,10 +1271,10 @@ class TestCreateFilter:
async def test_400_for_invalid_name(self, config_client: AsyncClient) -> None:
"""POST /api/config/filters returns 400 for invalid filter name."""
from app.services.config_file_service import FilterNameError
from app.services.filter_config_service import FilterNameError
with patch(
"app.routers.config.config_file_service.create_filter",
"app.routers.config.filter_config_service.create_filter",
AsyncMock(side_effect=FilterNameError("bad")),
):
resp = await config_client.post(
@@ -1304,7 +1304,7 @@ class TestDeleteFilter:
async def test_204_deletes_filter(self, config_client: AsyncClient) -> None:
"""DELETE /api/config/filters/my-custom returns 204."""
with patch(
"app.routers.config.config_file_service.delete_filter",
"app.routers.config.filter_config_service.delete_filter",
AsyncMock(return_value=None),
):
resp = await config_client.delete("/api/config/filters/my-custom")
@@ -1313,10 +1313,10 @@ class TestDeleteFilter:
async def test_404_for_unknown_filter(self, config_client: AsyncClient) -> None:
"""DELETE /api/config/filters/missing returns 404."""
from app.services.config_file_service import FilterNotFoundError
from app.services.filter_config_service import FilterNotFoundError
with patch(
"app.routers.config.config_file_service.delete_filter",
"app.routers.config.filter_config_service.delete_filter",
AsyncMock(side_effect=FilterNotFoundError("missing")),
):
resp = await config_client.delete("/api/config/filters/missing")
@@ -1325,10 +1325,10 @@ class TestDeleteFilter:
async def test_409_for_readonly_filter(self, config_client: AsyncClient) -> None:
"""DELETE /api/config/filters/sshd returns 409 for shipped conf-only filter."""
from app.services.config_file_service import FilterReadonlyError
from app.services.filter_config_service import FilterReadonlyError
with patch(
"app.routers.config.config_file_service.delete_filter",
"app.routers.config.filter_config_service.delete_filter",
AsyncMock(side_effect=FilterReadonlyError("sshd")),
):
resp = await config_client.delete("/api/config/filters/sshd")
@@ -1337,10 +1337,10 @@ class TestDeleteFilter:
async def test_400_for_invalid_name(self, config_client: AsyncClient) -> None:
"""DELETE /api/config/filters/... with bad name returns 400."""
from app.services.config_file_service import FilterNameError
from app.services.filter_config_service import FilterNameError
with patch(
"app.routers.config.config_file_service.delete_filter",
"app.routers.config.filter_config_service.delete_filter",
AsyncMock(side_effect=FilterNameError("bad")),
):
resp = await config_client.delete("/api/config/filters/bad")
@@ -1367,7 +1367,7 @@ class TestAssignFilterToJail:
async def test_204_assigns_filter(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/sshd/filter returns 204 on success."""
with patch(
"app.routers.config.config_file_service.assign_filter_to_jail",
"app.routers.config.filter_config_service.assign_filter_to_jail",
AsyncMock(return_value=None),
):
resp = await config_client.post(
@@ -1379,10 +1379,10 @@ class TestAssignFilterToJail:
async def test_404_for_unknown_jail(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/missing/filter returns 404."""
from app.services.config_file_service import JailNotFoundInConfigError
from app.services.jail_config_service import JailNotFoundInConfigError
with patch(
"app.routers.config.config_file_service.assign_filter_to_jail",
"app.routers.config.filter_config_service.assign_filter_to_jail",
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
):
resp = await config_client.post(
@@ -1394,10 +1394,10 @@ class TestAssignFilterToJail:
async def test_404_for_unknown_filter(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/sshd/filter returns 404 when filter not found."""
from app.services.config_file_service import FilterNotFoundError
from app.services.filter_config_service import FilterNotFoundError
with patch(
"app.routers.config.config_file_service.assign_filter_to_jail",
"app.routers.config.filter_config_service.assign_filter_to_jail",
AsyncMock(side_effect=FilterNotFoundError("missing-filter")),
):
resp = await config_client.post(
@@ -1409,10 +1409,10 @@ class TestAssignFilterToJail:
async def test_400_for_invalid_jail_name(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/.../filter with bad jail name returns 400."""
from app.services.config_file_service import JailNameError
from app.services.jail_config_service import JailNameError
with patch(
"app.routers.config.config_file_service.assign_filter_to_jail",
"app.routers.config.filter_config_service.assign_filter_to_jail",
AsyncMock(side_effect=JailNameError("bad")),
):
resp = await config_client.post(
@@ -1424,10 +1424,10 @@ class TestAssignFilterToJail:
async def test_400_for_invalid_filter_name(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/sshd/filter with bad filter name returns 400."""
from app.services.config_file_service import FilterNameError
from app.services.filter_config_service import FilterNameError
with patch(
"app.routers.config.config_file_service.assign_filter_to_jail",
"app.routers.config.filter_config_service.assign_filter_to_jail",
AsyncMock(side_effect=FilterNameError("bad")),
):
resp = await config_client.post(
@@ -1440,7 +1440,7 @@ class TestAssignFilterToJail:
async def test_reload_query_param_passed(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/sshd/filter?reload=true passes do_reload=True."""
with patch(
"app.routers.config.config_file_service.assign_filter_to_jail",
"app.routers.config.filter_config_service.assign_filter_to_jail",
AsyncMock(return_value=None),
) as mock_assign:
resp = await config_client.post(
@@ -1478,7 +1478,7 @@ class TestListActionsRouter:
mock_response = ActionListResponse(actions=[mock_action], total=1)
with patch(
"app.routers.config.config_file_service.list_actions",
"app.routers.config.action_config_service.list_actions",
AsyncMock(return_value=mock_response),
):
resp = await config_client.get("/api/config/actions")
@@ -1496,7 +1496,7 @@ class TestListActionsRouter:
mock_response = ActionListResponse(actions=[inactive, active], total=2)
with patch(
"app.routers.config.config_file_service.list_actions",
"app.routers.config.action_config_service.list_actions",
AsyncMock(return_value=mock_response),
):
resp = await config_client.get("/api/config/actions")
@@ -1524,7 +1524,7 @@ class TestGetActionRouter:
)
with patch(
"app.routers.config.config_file_service.get_action",
"app.routers.config.action_config_service.get_action",
AsyncMock(return_value=mock_action),
):
resp = await config_client.get("/api/config/actions/iptables")
@@ -1533,10 +1533,10 @@ class TestGetActionRouter:
assert resp.json()["name"] == "iptables"
async def test_404_when_not_found(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import ActionNotFoundError
from app.services.action_config_service import ActionNotFoundError
with patch(
"app.routers.config.config_file_service.get_action",
"app.routers.config.action_config_service.get_action",
AsyncMock(side_effect=ActionNotFoundError("missing")),
):
resp = await config_client.get("/api/config/actions/missing")
@@ -1563,7 +1563,7 @@ class TestUpdateActionRouter:
)
with patch(
"app.routers.config.config_file_service.update_action",
"app.routers.config.action_config_service.update_action",
AsyncMock(return_value=updated),
):
resp = await config_client.put(
@@ -1575,10 +1575,10 @@ class TestUpdateActionRouter:
assert resp.json()["actionban"] == "echo ban"
async def test_404_when_not_found(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import ActionNotFoundError
from app.services.action_config_service import ActionNotFoundError
with patch(
"app.routers.config.config_file_service.update_action",
"app.routers.config.action_config_service.update_action",
AsyncMock(side_effect=ActionNotFoundError("missing")),
):
resp = await config_client.put(
@@ -1588,10 +1588,10 @@ class TestUpdateActionRouter:
assert resp.status_code == 404
async def test_400_for_bad_name(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import ActionNameError
from app.services.action_config_service import ActionNameError
with patch(
"app.routers.config.config_file_service.update_action",
"app.routers.config.action_config_service.update_action",
AsyncMock(side_effect=ActionNameError()),
):
resp = await config_client.put(
@@ -1620,7 +1620,7 @@ class TestCreateActionRouter:
)
with patch(
"app.routers.config.config_file_service.create_action",
"app.routers.config.action_config_service.create_action",
AsyncMock(return_value=created),
):
resp = await config_client.post(
@@ -1632,10 +1632,10 @@ class TestCreateActionRouter:
assert resp.json()["name"] == "custom"
async def test_409_when_already_exists(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import ActionAlreadyExistsError
from app.services.action_config_service import ActionAlreadyExistsError
with patch(
"app.routers.config.config_file_service.create_action",
"app.routers.config.action_config_service.create_action",
AsyncMock(side_effect=ActionAlreadyExistsError("iptables")),
):
resp = await config_client.post(
@@ -1646,10 +1646,10 @@ class TestCreateActionRouter:
assert resp.status_code == 409
async def test_400_for_bad_name(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import ActionNameError
from app.services.action_config_service import ActionNameError
with patch(
"app.routers.config.config_file_service.create_action",
"app.routers.config.action_config_service.create_action",
AsyncMock(side_effect=ActionNameError()),
):
resp = await config_client.post(
@@ -1671,7 +1671,7 @@ class TestCreateActionRouter:
class TestDeleteActionRouter:
async def test_204_on_delete(self, config_client: AsyncClient) -> None:
with patch(
"app.routers.config.config_file_service.delete_action",
"app.routers.config.action_config_service.delete_action",
AsyncMock(return_value=None),
):
resp = await config_client.delete("/api/config/actions/custom")
@@ -1679,10 +1679,10 @@ class TestDeleteActionRouter:
assert resp.status_code == 204
async def test_404_when_not_found(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import ActionNotFoundError
from app.services.action_config_service import ActionNotFoundError
with patch(
"app.routers.config.config_file_service.delete_action",
"app.routers.config.action_config_service.delete_action",
AsyncMock(side_effect=ActionNotFoundError("missing")),
):
resp = await config_client.delete("/api/config/actions/missing")
@@ -1690,10 +1690,10 @@ class TestDeleteActionRouter:
assert resp.status_code == 404
async def test_409_when_readonly(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import ActionReadonlyError
from app.services.action_config_service import ActionReadonlyError
with patch(
"app.routers.config.config_file_service.delete_action",
"app.routers.config.action_config_service.delete_action",
AsyncMock(side_effect=ActionReadonlyError("iptables")),
):
resp = await config_client.delete("/api/config/actions/iptables")
@@ -1701,10 +1701,10 @@ class TestDeleteActionRouter:
assert resp.status_code == 409
async def test_400_for_bad_name(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import ActionNameError
from app.services.action_config_service import ActionNameError
with patch(
"app.routers.config.config_file_service.delete_action",
"app.routers.config.action_config_service.delete_action",
AsyncMock(side_effect=ActionNameError()),
):
resp = await config_client.delete("/api/config/actions/badname")
@@ -1723,7 +1723,7 @@ class TestDeleteActionRouter:
class TestAssignActionToJailRouter:
async def test_204_on_success(self, config_client: AsyncClient) -> None:
with patch(
"app.routers.config.config_file_service.assign_action_to_jail",
"app.routers.config.action_config_service.assign_action_to_jail",
AsyncMock(return_value=None),
):
resp = await config_client.post(
@@ -1734,10 +1734,10 @@ class TestAssignActionToJailRouter:
assert resp.status_code == 204
async def test_404_when_jail_not_found(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import JailNotFoundInConfigError
from app.services.jail_config_service import JailNotFoundInConfigError
with patch(
"app.routers.config.config_file_service.assign_action_to_jail",
"app.routers.config.action_config_service.assign_action_to_jail",
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
):
resp = await config_client.post(
@@ -1748,10 +1748,10 @@ class TestAssignActionToJailRouter:
assert resp.status_code == 404
async def test_404_when_action_not_found(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import ActionNotFoundError
from app.services.action_config_service import ActionNotFoundError
with patch(
"app.routers.config.config_file_service.assign_action_to_jail",
"app.routers.config.action_config_service.assign_action_to_jail",
AsyncMock(side_effect=ActionNotFoundError("missing")),
):
resp = await config_client.post(
@@ -1762,10 +1762,10 @@ class TestAssignActionToJailRouter:
assert resp.status_code == 404
async def test_400_for_bad_jail_name(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import JailNameError
from app.services.jail_config_service import JailNameError
with patch(
"app.routers.config.config_file_service.assign_action_to_jail",
"app.routers.config.action_config_service.assign_action_to_jail",
AsyncMock(side_effect=JailNameError()),
):
resp = await config_client.post(
@@ -1776,10 +1776,10 @@ class TestAssignActionToJailRouter:
assert resp.status_code == 400
async def test_400_for_bad_action_name(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import ActionNameError
from app.services.action_config_service import ActionNameError
with patch(
"app.routers.config.config_file_service.assign_action_to_jail",
"app.routers.config.action_config_service.assign_action_to_jail",
AsyncMock(side_effect=ActionNameError()),
):
resp = await config_client.post(
@@ -1791,7 +1791,7 @@ class TestAssignActionToJailRouter:
async def test_reload_param_passed(self, config_client: AsyncClient) -> None:
with patch(
"app.routers.config.config_file_service.assign_action_to_jail",
"app.routers.config.action_config_service.assign_action_to_jail",
AsyncMock(return_value=None),
) as mock_assign:
resp = await config_client.post(
@@ -1814,7 +1814,7 @@ class TestAssignActionToJailRouter:
class TestRemoveActionFromJailRouter:
async def test_204_on_success(self, config_client: AsyncClient) -> None:
with patch(
"app.routers.config.config_file_service.remove_action_from_jail",
"app.routers.config.action_config_service.remove_action_from_jail",
AsyncMock(return_value=None),
):
resp = await config_client.delete(
@@ -1824,10 +1824,10 @@ class TestRemoveActionFromJailRouter:
assert resp.status_code == 204
async def test_404_when_jail_not_found(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import JailNotFoundInConfigError
from app.services.jail_config_service import JailNotFoundInConfigError
with patch(
"app.routers.config.config_file_service.remove_action_from_jail",
"app.routers.config.action_config_service.remove_action_from_jail",
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
):
resp = await config_client.delete(
@@ -1837,10 +1837,10 @@ class TestRemoveActionFromJailRouter:
assert resp.status_code == 404
async def test_400_for_bad_jail_name(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import JailNameError
from app.services.jail_config_service import JailNameError
with patch(
"app.routers.config.config_file_service.remove_action_from_jail",
"app.routers.config.action_config_service.remove_action_from_jail",
AsyncMock(side_effect=JailNameError()),
):
resp = await config_client.delete(
@@ -1850,10 +1850,10 @@ class TestRemoveActionFromJailRouter:
assert resp.status_code == 400
async def test_400_for_bad_action_name(self, config_client: AsyncClient) -> None:
from app.services.config_file_service import ActionNameError
from app.services.action_config_service import ActionNameError
with patch(
"app.routers.config.config_file_service.remove_action_from_jail",
"app.routers.config.action_config_service.remove_action_from_jail",
AsyncMock(side_effect=ActionNameError()),
):
resp = await config_client.delete(
@@ -1864,7 +1864,7 @@ class TestRemoveActionFromJailRouter:
async def test_reload_param_passed(self, config_client: AsyncClient) -> None:
with patch(
"app.routers.config.config_file_service.remove_action_from_jail",
"app.routers.config.action_config_service.remove_action_from_jail",
AsyncMock(return_value=None),
) as mock_rm:
resp = await config_client.delete(
@@ -2060,7 +2060,7 @@ class TestValidateJailEndpoint:
jail_name="sshd", valid=True, issues=[]
)
with patch(
"app.routers.config.config_file_service.validate_jail_config",
"app.routers.config.jail_config_service.validate_jail_config",
AsyncMock(return_value=mock_result),
):
resp = await config_client.post("/api/config/jails/sshd/validate")
@@ -2080,7 +2080,7 @@ class TestValidateJailEndpoint:
jail_name="sshd", valid=False, issues=[issue]
)
with patch(
"app.routers.config.config_file_service.validate_jail_config",
"app.routers.config.jail_config_service.validate_jail_config",
AsyncMock(return_value=mock_result),
):
resp = await config_client.post("/api/config/jails/sshd/validate")
@@ -2093,10 +2093,10 @@ class TestValidateJailEndpoint:
async def test_400_for_invalid_jail_name(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/bad-name/validate returns 400 on JailNameError."""
from app.services.config_file_service import JailNameError
from app.services.jail_config_service import JailNameError
with patch(
"app.routers.config.config_file_service.validate_jail_config",
"app.routers.config.jail_config_service.validate_jail_config",
AsyncMock(side_effect=JailNameError("bad name")),
):
resp = await config_client.post("/api/config/jails/bad-name/validate")
@@ -2188,7 +2188,7 @@ class TestRollbackEndpoint:
message="Jail 'sshd' disabled and fail2ban restarted.",
)
with patch(
"app.routers.config.config_file_service.rollback_jail",
"app.routers.config.jail_config_service.rollback_jail",
AsyncMock(return_value=mock_result),
):
resp = await config_client.post("/api/config/jails/sshd/rollback")
@@ -2225,7 +2225,7 @@ class TestRollbackEndpoint:
message="fail2ban did not come back online.",
)
with patch(
"app.routers.config.config_file_service.rollback_jail",
"app.routers.config.jail_config_service.rollback_jail",
AsyncMock(return_value=mock_result),
):
resp = await config_client.post("/api/config/jails/sshd/rollback")
@@ -2238,10 +2238,10 @@ class TestRollbackEndpoint:
async def test_400_for_invalid_jail_name(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/bad/rollback returns 400 on JailNameError."""
from app.services.config_file_service import JailNameError
from app.services.jail_config_service import JailNameError
with patch(
"app.routers.config.config_file_service.rollback_jail",
"app.routers.config.jail_config_service.rollback_jail",
AsyncMock(side_effect=JailNameError("bad")),
):
resp = await config_client.post("/api/config/jails/bad/rollback")

View File

@@ -342,7 +342,7 @@ class TestListActionFiles:
)
resp_data = ActionListResponse(actions=[mock_action], total=1)
with patch(
"app.routers.config.config_file_service.list_actions",
"app.routers.config.action_config_service.list_actions",
AsyncMock(return_value=resp_data),
):
resp = await file_config_client.get("/api/config/actions")
@@ -365,7 +365,7 @@ class TestCreateActionFile:
actionban="echo ban <ip>",
)
with patch(
"app.routers.config.config_file_service.create_action",
"app.routers.config.action_config_service.create_action",
AsyncMock(return_value=created),
):
resp = await file_config_client.post(