Fix undefined names and config router imports / task status update

This commit is contained in:
2026-04-14 13:53:39 +02:00
parent 09c764cebc
commit 6b436dc354
6 changed files with 573 additions and 167 deletions

View File

@@ -101,7 +101,7 @@ class TestGetJailConfigs:
jails=[_make_jail_config("sshd")], total=1
)
with patch(
"app.routers.config.config_service.list_jail_configs",
"app.routers.jail_config.config_service.list_jail_configs",
AsyncMock(return_value=mock_response),
):
resp = await config_client.get("/api/config/jails")
@@ -124,7 +124,7 @@ class TestGetJailConfigs:
from app.utils.fail2ban_client import Fail2BanConnectionError
with patch(
"app.routers.config.config_service.list_jail_configs",
"app.routers.jail_config.config_service.list_jail_configs",
AsyncMock(side_effect=Fail2BanConnectionError("down", "/tmp/fake.sock")),
):
resp = await config_client.get("/api/config/jails")
@@ -144,7 +144,7 @@ class TestGetJailConfig:
"""GET /api/config/jails/sshd returns 200 with JailConfigResponse."""
mock_response = JailConfigResponse(jail=_make_jail_config("sshd"))
with patch(
"app.routers.config.config_service.get_jail_config",
"app.routers.jail_config.config_service.get_jail_config",
AsyncMock(return_value=mock_response),
):
resp = await config_client.get("/api/config/jails/sshd")
@@ -158,7 +158,7 @@ class TestGetJailConfig:
from app.services.config_service import JailNotFoundError
with patch(
"app.routers.config.config_service.get_jail_config",
"app.routers.jail_config.config_service.get_jail_config",
AsyncMock(side_effect=JailNotFoundError("missing")),
):
resp = await config_client.get("/api/config/jails/missing")
@@ -185,7 +185,7 @@ class TestUpdateJailConfig:
async def test_204_on_success(self, config_client: AsyncClient) -> None:
"""PUT /api/config/jails/sshd returns 204 on success."""
with patch(
"app.routers.config.config_service.update_jail_config",
"app.routers.jail_config.config_service.update_jail_config",
AsyncMock(return_value=None),
):
resp = await config_client.put(
@@ -200,7 +200,7 @@ class TestUpdateJailConfig:
from app.services.config_service import JailNotFoundError
with patch(
"app.routers.config.config_service.update_jail_config",
"app.routers.jail_config.config_service.update_jail_config",
AsyncMock(side_effect=JailNotFoundError("missing")),
):
resp = await config_client.put(
@@ -215,7 +215,7 @@ class TestUpdateJailConfig:
from app.services.config_service import ConfigValidationError
with patch(
"app.routers.config.config_service.update_jail_config",
"app.routers.jail_config.config_service.update_jail_config",
AsyncMock(side_effect=ConfigValidationError("bad regex")),
):
resp = await config_client.put(
@@ -230,7 +230,7 @@ class TestUpdateJailConfig:
from app.services.config_service import ConfigOperationError
with patch(
"app.routers.config.config_service.update_jail_config",
"app.routers.jail_config.config_service.update_jail_config",
AsyncMock(side_effect=ConfigOperationError("set failed")),
):
resp = await config_client.put(
@@ -243,7 +243,7 @@ class TestUpdateJailConfig:
async def test_204_with_dns_mode(self, config_client: AsyncClient) -> None:
"""PUT /api/config/jails/sshd accepts dns_mode field."""
with patch(
"app.routers.config.config_service.update_jail_config",
"app.routers.jail_config.config_service.update_jail_config",
AsyncMock(return_value=None),
):
resp = await config_client.put(
@@ -256,7 +256,7 @@ class TestUpdateJailConfig:
async def test_204_with_prefregex(self, config_client: AsyncClient) -> None:
"""PUT /api/config/jails/sshd accepts prefregex field."""
with patch(
"app.routers.config.config_service.update_jail_config",
"app.routers.jail_config.config_service.update_jail_config",
AsyncMock(return_value=None),
):
resp = await config_client.put(
@@ -269,7 +269,7 @@ class TestUpdateJailConfig:
async def test_204_with_date_pattern(self, config_client: AsyncClient) -> None:
"""PUT /api/config/jails/sshd accepts date_pattern field."""
with patch(
"app.routers.config.config_service.update_jail_config",
"app.routers.jail_config.config_service.update_jail_config",
AsyncMock(return_value=None),
):
resp = await config_client.put(
@@ -297,7 +297,7 @@ class TestGetGlobalConfig:
db_max_matches=10,
)
with patch(
"app.routers.config.config_service.get_global_config",
"app.routers.config_misc.config_service.get_global_config",
AsyncMock(return_value=mock_response),
):
resp = await config_client.get("/api/config/global")
@@ -327,7 +327,7 @@ class TestUpdateGlobalConfig:
async def test_204_on_success(self, config_client: AsyncClient) -> None:
"""PUT /api/config/global returns 204 on success."""
with patch(
"app.routers.config.config_service.update_global_config",
"app.routers.config_misc.config_service.update_global_config",
AsyncMock(return_value=None),
):
resp = await config_client.put(
@@ -342,7 +342,7 @@ class TestUpdateGlobalConfig:
from app.services.config_service import ConfigOperationError
with patch(
"app.routers.config.config_service.update_global_config",
"app.routers.config_misc.config_service.update_global_config",
AsyncMock(side_effect=ConfigOperationError("set failed")),
):
resp = await config_client.put(
@@ -364,7 +364,7 @@ class TestReloadFail2ban:
async def test_204_on_success(self, config_client: AsyncClient) -> None:
"""POST /api/config/reload returns 204 on success."""
with patch(
"app.routers.config.jail_service.reload_all",
"app.routers.config_misc.jail_service.reload_all",
AsyncMock(return_value=None),
):
resp = await config_client.post("/api/config/reload")
@@ -376,7 +376,7 @@ class TestReloadFail2ban:
from app.utils.fail2ban_client import Fail2BanConnectionError
with patch(
"app.routers.config.jail_service.reload_all",
"app.routers.config_misc.jail_service.reload_all",
AsyncMock(side_effect=Fail2BanConnectionError("no socket", "/fake.sock")),
):
resp = await config_client.post("/api/config/reload")
@@ -388,7 +388,7 @@ class TestReloadFail2ban:
from app.services.jail_service import JailOperationError
with patch(
"app.routers.config.jail_service.reload_all",
"app.routers.config_misc.jail_service.reload_all",
AsyncMock(side_effect=JailOperationError("reload rejected")),
):
resp = await config_client.post("/api/config/reload")
@@ -408,15 +408,15 @@ class TestRestartFail2ban:
"""POST /api/config/restart returns 204 when fail2ban restarts cleanly."""
with (
patch(
"app.routers.config.jail_service.restart",
"app.routers.config_misc.jail_service.restart",
AsyncMock(return_value=None),
),
patch(
"app.routers.config.config_file_service.start_daemon",
"app.routers.config_misc.config_file_service.start_daemon",
AsyncMock(return_value=True),
),
patch(
"app.routers.config.config_file_service.wait_for_fail2ban",
"app.routers.config_misc.config_file_service.wait_for_fail2ban",
AsyncMock(return_value=True),
),
):
@@ -428,15 +428,15 @@ class TestRestartFail2ban:
"""POST /api/config/restart returns 503 when fail2ban does not come back online."""
with (
patch(
"app.routers.config.jail_service.restart",
"app.routers.config_misc.jail_service.restart",
AsyncMock(return_value=None),
),
patch(
"app.routers.config.config_file_service.start_daemon",
"app.routers.config_misc.config_file_service.start_daemon",
AsyncMock(return_value=True),
),
patch(
"app.routers.config.config_file_service.wait_for_fail2ban",
"app.routers.config_misc.config_file_service.wait_for_fail2ban",
AsyncMock(return_value=False),
),
):
@@ -449,7 +449,7 @@ class TestRestartFail2ban:
from app.services.jail_service import JailOperationError
with patch(
"app.routers.config.jail_service.restart",
"app.routers.config_misc.jail_service.restart",
AsyncMock(side_effect=JailOperationError("stop failed")),
):
resp = await config_client.post("/api/config/restart")
@@ -461,7 +461,7 @@ class TestRestartFail2ban:
from app.utils.fail2ban_client import Fail2BanConnectionError
with patch(
"app.routers.config.jail_service.restart",
"app.routers.config_misc.jail_service.restart",
AsyncMock(side_effect=Fail2BanConnectionError("no socket", "/fake.sock")),
):
resp = await config_client.post("/api/config/restart")
@@ -473,15 +473,15 @@ class TestRestartFail2ban:
mock_start = AsyncMock(return_value=True)
with (
patch(
"app.routers.config.jail_service.restart",
"app.routers.config_misc.jail_service.restart",
AsyncMock(return_value=None),
),
patch(
"app.routers.config.config_file_service.start_daemon",
"app.routers.config_misc.config_file_service.start_daemon",
mock_start,
),
patch(
"app.routers.config.config_file_service.wait_for_fail2ban",
"app.routers.config_misc.config_file_service.wait_for_fail2ban",
AsyncMock(return_value=True),
),
):
@@ -502,7 +502,7 @@ class TestRegexTest:
"""POST /api/config/regex-test returns matched=true for a valid match."""
mock_response = RegexTestResponse(matched=True, groups=["1.2.3.4"], error=None)
with patch(
"app.routers.config.log_service.test_regex",
"app.routers.config_misc.log_service.test_regex",
return_value=mock_response,
):
resp = await config_client.post(
@@ -520,7 +520,7 @@ class TestRegexTest:
"""POST /api/config/regex-test returns matched=false for no match."""
mock_response = RegexTestResponse(matched=False, groups=[], error=None)
with patch(
"app.routers.config.log_service.test_regex",
"app.routers.config_misc.log_service.test_regex",
return_value=mock_response,
):
resp = await config_client.post(
@@ -554,7 +554,7 @@ class TestAddLogPath:
async def test_204_on_success(self, config_client: AsyncClient) -> None:
"""POST /api/config/jails/sshd/logpath returns 204 on success."""
with patch(
"app.routers.config.config_service.add_log_path",
"app.routers.jail_config.config_service.add_log_path",
AsyncMock(return_value=None),
):
resp = await config_client.post(
@@ -569,7 +569,7 @@ class TestAddLogPath:
from app.services.config_service import JailNotFoundError
with patch(
"app.routers.config.config_service.add_log_path",
"app.routers.jail_config.config_service.add_log_path",
AsyncMock(side_effect=JailNotFoundError("missing")),
):
resp = await config_client.post(
@@ -598,7 +598,7 @@ class TestPreviewLog:
matched_count=1,
)
with patch(
"app.routers.config.log_service.preview_log",
"app.routers.config_misc.log_service.preview_log",
AsyncMock(return_value=mock_response),
):
resp = await config_client.post(
@@ -726,7 +726,7 @@ class TestGetInactiveJails:
mock_response = InactiveJailListResponse(jails=[mock_jail], total=1)
with patch(
"app.routers.config.jail_config_service.list_inactive_jails",
"app.routers.jail_config.jail_config_service.list_inactive_jails",
AsyncMock(return_value=mock_response),
):
resp = await config_client.get("/api/config/jails/inactive")
@@ -741,7 +741,7 @@ class TestGetInactiveJails:
from app.models.config import InactiveJailListResponse
with patch(
"app.routers.config.jail_config_service.list_inactive_jails",
"app.routers.jail_config.jail_config_service.list_inactive_jails",
AsyncMock(return_value=InactiveJailListResponse(jails=[], total=0)),
):
resp = await config_client.get("/api/config/jails/inactive")
@@ -777,7 +777,7 @@ class TestActivateJail:
message="Jail 'apache-auth' activated successfully.",
)
with patch(
"app.routers.config.jail_config_service.activate_jail",
"app.routers.jail_config.jail_config_service.activate_jail",
AsyncMock(return_value=mock_response),
):
resp = await config_client.post(
@@ -797,7 +797,7 @@ class TestActivateJail:
name="apache-auth", active=True, message="Activated."
)
with patch(
"app.routers.config.jail_config_service.activate_jail",
"app.routers.jail_config.jail_config_service.activate_jail",
AsyncMock(return_value=mock_response),
) as mock_activate:
resp = await config_client.post(
@@ -816,7 +816,7 @@ class TestActivateJail:
from app.services.jail_config_service import JailNotFoundInConfigError
with patch(
"app.routers.config.jail_config_service.activate_jail",
"app.routers.jail_config.jail_config_service.activate_jail",
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
):
resp = await config_client.post(
@@ -830,7 +830,7 @@ class TestActivateJail:
from app.services.jail_config_service import JailAlreadyActiveError
with patch(
"app.routers.config.jail_config_service.activate_jail",
"app.routers.jail_config.jail_config_service.activate_jail",
AsyncMock(side_effect=JailAlreadyActiveError("sshd")),
):
resp = await config_client.post(
@@ -841,10 +841,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.jail_config_service import JailNameError
from app.exceptions import JailNameError
with patch(
"app.routers.config.jail_config_service.activate_jail",
"app.routers.jail_config.jail_config_service.activate_jail",
AsyncMock(side_effect=JailNameError("bad name")),
):
resp = await config_client.post(
@@ -873,7 +873,7 @@ class TestActivateJail:
message="Jail 'airsonic-auth' cannot be activated: log file '/var/log/airsonic/airsonic.log' not found",
)
with patch(
"app.routers.config.jail_config_service.activate_jail",
"app.routers.jail_config.jail_config_service.activate_jail",
AsyncMock(return_value=blocked_response),
):
resp = await config_client.post(
@@ -906,7 +906,7 @@ class TestDeactivateJail:
message="Jail 'sshd' deactivated successfully.",
)
with patch(
"app.routers.config.jail_config_service.deactivate_jail",
"app.routers.jail_config.jail_config_service.deactivate_jail",
AsyncMock(return_value=mock_response),
):
resp = await config_client.post("/api/config/jails/sshd/deactivate")
@@ -921,7 +921,7 @@ class TestDeactivateJail:
from app.services.jail_config_service import JailNotFoundInConfigError
with patch(
"app.routers.config.jail_config_service.deactivate_jail",
"app.routers.jail_config.jail_config_service.deactivate_jail",
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
):
resp = await config_client.post(
@@ -935,7 +935,7 @@ class TestDeactivateJail:
from app.services.jail_config_service import JailAlreadyInactiveError
with patch(
"app.routers.config.jail_config_service.deactivate_jail",
"app.routers.jail_config.jail_config_service.deactivate_jail",
AsyncMock(side_effect=JailAlreadyInactiveError("apache-auth")),
):
resp = await config_client.post(
@@ -946,10 +946,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.jail_config_service import JailNameError
from app.exceptions import JailNameError
with patch(
"app.routers.config.jail_config_service.deactivate_jail",
"app.routers.jail_config.jail_config_service.deactivate_jail",
AsyncMock(side_effect=JailNameError("bad")),
):
resp = await config_client.post(
@@ -977,7 +977,7 @@ class TestDeactivateJail:
)
with (
patch(
"app.routers.config.jail_config_service._deactivate_jail",
"app.routers.jail_config.jail_config_service._deactivate_jail",
AsyncMock(return_value=mock_response),
),
patch(
@@ -1028,7 +1028,7 @@ class TestListFilters:
total=1,
)
with patch(
"app.routers.config.filter_config_service.list_filters",
"app.routers.filter_config.filter_config_service.list_filters",
AsyncMock(return_value=mock_response),
):
resp = await config_client.get("/api/config/filters")
@@ -1044,7 +1044,7 @@ class TestListFilters:
from app.models.config import FilterListResponse
with patch(
"app.routers.config.filter_config_service.list_filters",
"app.routers.filter_config.filter_config_service.list_filters",
AsyncMock(return_value=FilterListResponse(filters=[], total=0)),
):
resp = await config_client.get("/api/config/filters")
@@ -1067,7 +1067,7 @@ class TestListFilters:
total=2,
)
with patch(
"app.routers.config.filter_config_service.list_filters",
"app.routers.filter_config.filter_config_service.list_filters",
AsyncMock(return_value=mock_response),
):
resp = await config_client.get("/api/config/filters")
@@ -1096,7 +1096,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.filter_config_service.get_filter",
"app.routers.filter_config.filter_config_service.get_filter",
AsyncMock(return_value=_make_filter_config("sshd")),
):
resp = await config_client.get("/api/config/filters/sshd")
@@ -1112,7 +1112,7 @@ class TestGetFilter:
from app.services.filter_config_service import FilterNotFoundError
with patch(
"app.routers.config.filter_config_service.get_filter",
"app.routers.filter_config.filter_config_service.get_filter",
AsyncMock(side_effect=FilterNotFoundError("missing")),
):
resp = await config_client.get("/api/config/filters/missing")
@@ -1139,7 +1139,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.filter_config_service.update_filter",
"app.routers.filter_config.filter_config_service.update_filter",
AsyncMock(return_value=_make_filter_config("sshd")),
):
resp = await config_client.put(
@@ -1155,7 +1155,7 @@ class TestUpdateFilter:
from app.services.filter_config_service import FilterNotFoundError
with patch(
"app.routers.config.filter_config_service.update_filter",
"app.routers.filter_config.filter_config_service.update_filter",
AsyncMock(side_effect=FilterNotFoundError("missing")),
):
resp = await config_client.put(
@@ -1170,7 +1170,7 @@ class TestUpdateFilter:
from app.services.filter_config_service import FilterInvalidRegexError
with patch(
"app.routers.config.filter_config_service.update_filter",
"app.routers.filter_config.filter_config_service.update_filter",
AsyncMock(side_effect=FilterInvalidRegexError("[bad", "unterminated")),
):
resp = await config_client.put(
@@ -1182,10 +1182,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.filter_config_service import FilterNameError
from app.exceptions import FilterNameError
with patch(
"app.routers.config.filter_config_service.update_filter",
"app.routers.filter_config.filter_config_service.update_filter",
AsyncMock(side_effect=FilterNameError("bad")),
):
resp = await config_client.put(
@@ -1198,7 +1198,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.filter_config_service.update_filter",
"app.routers.filter_config.filter_config_service.update_filter",
AsyncMock(return_value=_make_filter_config("sshd")),
) as mock_update:
resp = await config_client.put(
@@ -1229,7 +1229,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.filter_config_service.create_filter",
"app.routers.filter_config.filter_config_service.create_filter",
AsyncMock(return_value=_make_filter_config("my-custom")),
):
resp = await config_client.post(
@@ -1245,7 +1245,7 @@ class TestCreateFilter:
from app.services.filter_config_service import FilterAlreadyExistsError
with patch(
"app.routers.config.filter_config_service.create_filter",
"app.routers.filter_config.filter_config_service.create_filter",
AsyncMock(side_effect=FilterAlreadyExistsError("sshd")),
):
resp = await config_client.post(
@@ -1260,7 +1260,7 @@ class TestCreateFilter:
from app.services.filter_config_service import FilterInvalidRegexError
with patch(
"app.routers.config.filter_config_service.create_filter",
"app.routers.filter_config.filter_config_service.create_filter",
AsyncMock(side_effect=FilterInvalidRegexError("[bad", "unterminated")),
):
resp = await config_client.post(
@@ -1272,10 +1272,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.filter_config_service import FilterNameError
from app.exceptions import FilterNameError
with patch(
"app.routers.config.filter_config_service.create_filter",
"app.routers.filter_config.filter_config_service.create_filter",
AsyncMock(side_effect=FilterNameError("bad")),
):
resp = await config_client.post(
@@ -1305,7 +1305,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.filter_config_service.delete_filter",
"app.routers.filter_config.filter_config_service.delete_filter",
AsyncMock(return_value=None),
):
resp = await config_client.delete("/api/config/filters/my-custom")
@@ -1317,7 +1317,7 @@ class TestDeleteFilter:
from app.services.filter_config_service import FilterNotFoundError
with patch(
"app.routers.config.filter_config_service.delete_filter",
"app.routers.filter_config.filter_config_service.delete_filter",
AsyncMock(side_effect=FilterNotFoundError("missing")),
):
resp = await config_client.delete("/api/config/filters/missing")
@@ -1329,7 +1329,7 @@ class TestDeleteFilter:
from app.services.filter_config_service import FilterReadonlyError
with patch(
"app.routers.config.filter_config_service.delete_filter",
"app.routers.filter_config.filter_config_service.delete_filter",
AsyncMock(side_effect=FilterReadonlyError("sshd")),
):
resp = await config_client.delete("/api/config/filters/sshd")
@@ -1338,10 +1338,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.filter_config_service import FilterNameError
from app.exceptions import FilterNameError
with patch(
"app.routers.config.filter_config_service.delete_filter",
"app.routers.filter_config.filter_config_service.delete_filter",
AsyncMock(side_effect=FilterNameError("bad")),
):
resp = await config_client.delete("/api/config/filters/bad")
@@ -1368,7 +1368,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.filter_config_service.assign_filter_to_jail",
"app.routers.filter_config.filter_config_service.assign_filter_to_jail",
AsyncMock(return_value=None),
):
resp = await config_client.post(
@@ -1383,7 +1383,7 @@ class TestAssignFilterToJail:
from app.services.jail_config_service import JailNotFoundInConfigError
with patch(
"app.routers.config.filter_config_service.assign_filter_to_jail",
"app.routers.filter_config.filter_config_service.assign_filter_to_jail",
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
):
resp = await config_client.post(
@@ -1398,7 +1398,7 @@ class TestAssignFilterToJail:
from app.services.filter_config_service import FilterNotFoundError
with patch(
"app.routers.config.filter_config_service.assign_filter_to_jail",
"app.routers.filter_config.filter_config_service.assign_filter_to_jail",
AsyncMock(side_effect=FilterNotFoundError("missing-filter")),
):
resp = await config_client.post(
@@ -1410,10 +1410,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.jail_config_service import JailNameError
from app.exceptions import JailNameError
with patch(
"app.routers.config.filter_config_service.assign_filter_to_jail",
"app.routers.filter_config.filter_config_service.assign_filter_to_jail",
AsyncMock(side_effect=JailNameError("bad")),
):
resp = await config_client.post(
@@ -1425,10 +1425,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.filter_config_service import FilterNameError
from app.exceptions import FilterNameError
with patch(
"app.routers.config.filter_config_service.assign_filter_to_jail",
"app.routers.filter_config.filter_config_service.assign_filter_to_jail",
AsyncMock(side_effect=FilterNameError("bad")),
):
resp = await config_client.post(
@@ -1441,7 +1441,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.filter_config_service.assign_filter_to_jail",
"app.routers.filter_config.filter_config_service.assign_filter_to_jail",
AsyncMock(return_value=None),
) as mock_assign:
resp = await config_client.post(
@@ -1479,7 +1479,7 @@ class TestListActionsRouter:
mock_response = ActionListResponse(actions=[mock_action], total=1)
with patch(
"app.routers.config.action_config_service.list_actions",
"app.routers.action_config.action_config_service.list_actions",
AsyncMock(return_value=mock_response),
):
resp = await config_client.get("/api/config/actions")
@@ -1497,7 +1497,7 @@ class TestListActionsRouter:
mock_response = ActionListResponse(actions=[inactive, active], total=2)
with patch(
"app.routers.config.action_config_service.list_actions",
"app.routers.action_config.action_config_service.list_actions",
AsyncMock(return_value=mock_response),
):
resp = await config_client.get("/api/config/actions")
@@ -1525,7 +1525,7 @@ class TestGetActionRouter:
)
with patch(
"app.routers.config.action_config_service.get_action",
"app.routers.action_config.action_config_service.get_action",
AsyncMock(return_value=mock_action),
):
resp = await config_client.get("/api/config/actions/iptables")
@@ -1537,7 +1537,7 @@ class TestGetActionRouter:
from app.services.action_config_service import ActionNotFoundError
with patch(
"app.routers.config.action_config_service.get_action",
"app.routers.action_config.action_config_service.get_action",
AsyncMock(side_effect=ActionNotFoundError("missing")),
):
resp = await config_client.get("/api/config/actions/missing")
@@ -1564,7 +1564,7 @@ class TestUpdateActionRouter:
)
with patch(
"app.routers.config.action_config_service.update_action",
"app.routers.action_config.action_config_service.update_action",
AsyncMock(return_value=updated),
):
resp = await config_client.put(
@@ -1579,7 +1579,7 @@ class TestUpdateActionRouter:
from app.services.action_config_service import ActionNotFoundError
with patch(
"app.routers.config.action_config_service.update_action",
"app.routers.action_config.action_config_service.update_action",
AsyncMock(side_effect=ActionNotFoundError("missing")),
):
resp = await config_client.put(
@@ -1589,10 +1589,10 @@ class TestUpdateActionRouter:
assert resp.status_code == 404
async def test_400_for_bad_name(self, config_client: AsyncClient) -> None:
from app.services.action_config_service import ActionNameError
from app.exceptions import ActionNameError
with patch(
"app.routers.config.action_config_service.update_action",
"app.routers.action_config.action_config_service.update_action",
AsyncMock(side_effect=ActionNameError()),
):
resp = await config_client.put(
@@ -1621,7 +1621,7 @@ class TestCreateActionRouter:
)
with patch(
"app.routers.config.action_config_service.create_action",
"app.routers.action_config.action_config_service.create_action",
AsyncMock(return_value=created),
):
resp = await config_client.post(
@@ -1636,7 +1636,7 @@ class TestCreateActionRouter:
from app.services.action_config_service import ActionAlreadyExistsError
with patch(
"app.routers.config.action_config_service.create_action",
"app.routers.action_config.action_config_service.create_action",
AsyncMock(side_effect=ActionAlreadyExistsError("iptables")),
):
resp = await config_client.post(
@@ -1647,10 +1647,10 @@ class TestCreateActionRouter:
assert resp.status_code == 409
async def test_400_for_bad_name(self, config_client: AsyncClient) -> None:
from app.services.action_config_service import ActionNameError
from app.exceptions import ActionNameError
with patch(
"app.routers.config.action_config_service.create_action",
"app.routers.action_config.action_config_service.create_action",
AsyncMock(side_effect=ActionNameError()),
):
resp = await config_client.post(
@@ -1672,7 +1672,7 @@ class TestCreateActionRouter:
class TestDeleteActionRouter:
async def test_204_on_delete(self, config_client: AsyncClient) -> None:
with patch(
"app.routers.config.action_config_service.delete_action",
"app.routers.action_config.action_config_service.delete_action",
AsyncMock(return_value=None),
):
resp = await config_client.delete("/api/config/actions/custom")
@@ -1683,7 +1683,7 @@ class TestDeleteActionRouter:
from app.services.action_config_service import ActionNotFoundError
with patch(
"app.routers.config.action_config_service.delete_action",
"app.routers.action_config.action_config_service.delete_action",
AsyncMock(side_effect=ActionNotFoundError("missing")),
):
resp = await config_client.delete("/api/config/actions/missing")
@@ -1694,7 +1694,7 @@ class TestDeleteActionRouter:
from app.services.action_config_service import ActionReadonlyError
with patch(
"app.routers.config.action_config_service.delete_action",
"app.routers.action_config.action_config_service.delete_action",
AsyncMock(side_effect=ActionReadonlyError("iptables")),
):
resp = await config_client.delete("/api/config/actions/iptables")
@@ -1702,10 +1702,10 @@ class TestDeleteActionRouter:
assert resp.status_code == 409
async def test_400_for_bad_name(self, config_client: AsyncClient) -> None:
from app.services.action_config_service import ActionNameError
from app.exceptions import ActionNameError
with patch(
"app.routers.config.action_config_service.delete_action",
"app.routers.action_config.action_config_service.delete_action",
AsyncMock(side_effect=ActionNameError()),
):
resp = await config_client.delete("/api/config/actions/badname")
@@ -1724,7 +1724,7 @@ class TestDeleteActionRouter:
class TestAssignActionToJailRouter:
async def test_204_on_success(self, config_client: AsyncClient) -> None:
with patch(
"app.routers.config.action_config_service.assign_action_to_jail",
"app.routers.action_config.action_config_service.assign_action_to_jail",
AsyncMock(return_value=None),
):
resp = await config_client.post(
@@ -1738,7 +1738,7 @@ class TestAssignActionToJailRouter:
from app.services.jail_config_service import JailNotFoundInConfigError
with patch(
"app.routers.config.action_config_service.assign_action_to_jail",
"app.routers.action_config.action_config_service.assign_action_to_jail",
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
):
resp = await config_client.post(
@@ -1752,7 +1752,7 @@ class TestAssignActionToJailRouter:
from app.services.action_config_service import ActionNotFoundError
with patch(
"app.routers.config.action_config_service.assign_action_to_jail",
"app.routers.action_config.action_config_service.assign_action_to_jail",
AsyncMock(side_effect=ActionNotFoundError("missing")),
):
resp = await config_client.post(
@@ -1763,10 +1763,10 @@ class TestAssignActionToJailRouter:
assert resp.status_code == 404
async def test_400_for_bad_jail_name(self, config_client: AsyncClient) -> None:
from app.services.jail_config_service import JailNameError
from app.exceptions import JailNameError
with patch(
"app.routers.config.action_config_service.assign_action_to_jail",
"app.routers.action_config.action_config_service.assign_action_to_jail",
AsyncMock(side_effect=JailNameError()),
):
resp = await config_client.post(
@@ -1777,10 +1777,10 @@ class TestAssignActionToJailRouter:
assert resp.status_code == 400
async def test_400_for_bad_action_name(self, config_client: AsyncClient) -> None:
from app.services.action_config_service import ActionNameError
from app.exceptions import ActionNameError
with patch(
"app.routers.config.action_config_service.assign_action_to_jail",
"app.routers.action_config.action_config_service.assign_action_to_jail",
AsyncMock(side_effect=ActionNameError()),
):
resp = await config_client.post(
@@ -1792,7 +1792,7 @@ class TestAssignActionToJailRouter:
async def test_reload_param_passed(self, config_client: AsyncClient) -> None:
with patch(
"app.routers.config.action_config_service.assign_action_to_jail",
"app.routers.action_config.action_config_service.assign_action_to_jail",
AsyncMock(return_value=None),
) as mock_assign:
resp = await config_client.post(
@@ -1815,7 +1815,7 @@ class TestAssignActionToJailRouter:
class TestRemoveActionFromJailRouter:
async def test_204_on_success(self, config_client: AsyncClient) -> None:
with patch(
"app.routers.config.action_config_service.remove_action_from_jail",
"app.routers.action_config.action_config_service.remove_action_from_jail",
AsyncMock(return_value=None),
):
resp = await config_client.delete(
@@ -1828,7 +1828,7 @@ class TestRemoveActionFromJailRouter:
from app.services.jail_config_service import JailNotFoundInConfigError
with patch(
"app.routers.config.action_config_service.remove_action_from_jail",
"app.routers.action_config.action_config_service.remove_action_from_jail",
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
):
resp = await config_client.delete(
@@ -1838,10 +1838,10 @@ class TestRemoveActionFromJailRouter:
assert resp.status_code == 404
async def test_400_for_bad_jail_name(self, config_client: AsyncClient) -> None:
from app.services.jail_config_service import JailNameError
from app.exceptions import JailNameError
with patch(
"app.routers.config.action_config_service.remove_action_from_jail",
"app.routers.action_config.action_config_service.remove_action_from_jail",
AsyncMock(side_effect=JailNameError()),
):
resp = await config_client.delete(
@@ -1851,10 +1851,10 @@ class TestRemoveActionFromJailRouter:
assert resp.status_code == 400
async def test_400_for_bad_action_name(self, config_client: AsyncClient) -> None:
from app.services.action_config_service import ActionNameError
from app.exceptions import ActionNameError
with patch(
"app.routers.config.action_config_service.remove_action_from_jail",
"app.routers.action_config.action_config_service.remove_action_from_jail",
AsyncMock(side_effect=ActionNameError()),
):
resp = await config_client.delete(
@@ -1865,7 +1865,7 @@ class TestRemoveActionFromJailRouter:
async def test_reload_param_passed(self, config_client: AsyncClient) -> None:
with patch(
"app.routers.config.action_config_service.remove_action_from_jail",
"app.routers.action_config.action_config_service.remove_action_from_jail",
AsyncMock(return_value=None),
) as mock_rm:
resp = await config_client.delete(
@@ -1903,7 +1903,7 @@ class TestGetFail2BanLog:
async def test_200_returns_log_response(self, config_client: AsyncClient) -> None:
"""GET /api/config/fail2ban-log returns 200 with Fail2BanLogResponse."""
with patch(
"app.routers.config.config_service.read_fail2ban_log",
"app.routers.config_misc.config_service.read_fail2ban_log",
AsyncMock(return_value=self._mock_log_response()),
):
resp = await config_client.get("/api/config/fail2ban-log")
@@ -1918,7 +1918,7 @@ class TestGetFail2BanLog:
async def test_200_passes_lines_query_param(self, config_client: AsyncClient) -> None:
"""GET /api/config/fail2ban-log passes the lines query param to the service."""
with patch(
"app.routers.config.config_service.read_fail2ban_log",
"app.routers.config_misc.config_service.read_fail2ban_log",
AsyncMock(return_value=self._mock_log_response()),
) as mock_fn:
resp = await config_client.get("/api/config/fail2ban-log?lines=500")
@@ -1930,7 +1930,7 @@ class TestGetFail2BanLog:
async def test_200_passes_filter_query_param(self, config_client: AsyncClient) -> None:
"""GET /api/config/fail2ban-log passes the filter query param to the service."""
with patch(
"app.routers.config.config_service.read_fail2ban_log",
"app.routers.config_misc.config_service.read_fail2ban_log",
AsyncMock(return_value=self._mock_log_response()),
) as mock_fn:
resp = await config_client.get("/api/config/fail2ban-log?filter=ERROR")
@@ -1944,7 +1944,7 @@ class TestGetFail2BanLog:
from app.services.config_service import ConfigOperationError
with patch(
"app.routers.config.config_service.read_fail2ban_log",
"app.routers.config_misc.config_service.read_fail2ban_log",
AsyncMock(side_effect=ConfigOperationError("fail2ban is logging to 'STDOUT'")),
):
resp = await config_client.get("/api/config/fail2ban-log")
@@ -1956,7 +1956,7 @@ class TestGetFail2BanLog:
from app.services.config_service import ConfigOperationError
with patch(
"app.routers.config.config_service.read_fail2ban_log",
"app.routers.config_misc.config_service.read_fail2ban_log",
AsyncMock(side_effect=ConfigOperationError("outside the allowed directory")),
):
resp = await config_client.get("/api/config/fail2ban-log")
@@ -1968,7 +1968,7 @@ class TestGetFail2BanLog:
from app.utils.fail2ban_client import Fail2BanConnectionError
with patch(
"app.routers.config.config_service.read_fail2ban_log",
"app.routers.config_misc.config_service.read_fail2ban_log",
AsyncMock(side_effect=Fail2BanConnectionError("socket error", "/tmp/f.sock")),
):
resp = await config_client.get("/api/config/fail2ban-log")
@@ -2011,7 +2011,7 @@ class TestGetServiceStatus:
async def test_200_when_online(self, config_client: AsyncClient) -> None:
"""GET /api/config/service-status returns 200 with full status when online."""
with patch(
"app.routers.config.config_service.get_service_status",
"app.routers.config_misc.config_service.get_service_status",
AsyncMock(return_value=self._mock_status(online=True)),
):
resp = await config_client.get("/api/config/service-status")
@@ -2026,7 +2026,7 @@ class TestGetServiceStatus:
async def test_200_when_offline(self, config_client: AsyncClient) -> None:
"""GET /api/config/service-status returns 200 with offline=False when daemon is down."""
with patch(
"app.routers.config.config_service.get_service_status",
"app.routers.config_misc.config_service.get_service_status",
AsyncMock(return_value=self._mock_status(online=False)),
):
resp = await config_client.get("/api/config/service-status")
@@ -2063,7 +2063,7 @@ class TestValidateJailEndpoint:
jail_name="sshd", valid=True, issues=[]
)
with patch(
"app.routers.config.jail_config_service.validate_jail_config",
"app.routers.jail_config.jail_config_service.validate_jail_config",
AsyncMock(return_value=mock_result),
):
resp = await config_client.post("/api/config/jails/sshd/validate")
@@ -2083,7 +2083,7 @@ class TestValidateJailEndpoint:
jail_name="sshd", valid=False, issues=[issue]
)
with patch(
"app.routers.config.jail_config_service.validate_jail_config",
"app.routers.jail_config.jail_config_service.validate_jail_config",
AsyncMock(return_value=mock_result),
):
resp = await config_client.post("/api/config/jails/sshd/validate")
@@ -2096,10 +2096,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.jail_config_service import JailNameError
from app.exceptions import JailNameError
with patch(
"app.routers.config.jail_config_service.validate_jail_config",
"app.routers.jail_config.jail_config_service.validate_jail_config",
AsyncMock(side_effect=JailNameError("bad name")),
):
resp = await config_client.post("/api/config/jails/bad-name/validate")
@@ -2126,7 +2126,7 @@ class TestPendingRecovery:
app = config_client._transport.app # type: ignore[attr-defined]
app.state.pending_recovery = None
resp = await config_client.get("/api/config/pending-recovery")
resp = await config_client.get("/api/config/jails/pending-recovery")
assert resp.status_code == 200
assert resp.json() is None
@@ -2146,7 +2146,7 @@ class TestPendingRecovery:
app = config_client._transport.app # type: ignore[attr-defined]
app.state.pending_recovery = record
resp = await config_client.get("/api/config/pending-recovery")
resp = await config_client.get("/api/config/jails/pending-recovery")
assert resp.status_code == 200
data = resp.json()
@@ -2158,7 +2158,7 @@ class TestPendingRecovery:
resp = await AsyncClient(
transport=ASGITransport(app=config_client._transport.app), # type: ignore[attr-defined]
base_url="http://test",
).get("/api/config/pending-recovery")
).get("/api/config/jails/pending-recovery")
assert resp.status_code == 401
@@ -2191,7 +2191,7 @@ class TestRollbackEndpoint:
message="Jail 'sshd' disabled and fail2ban restarted.",
)
with patch(
"app.routers.config.jail_config_service._rollback_jail",
"app.routers.jail_config.jail_config_service._rollback_jail",
AsyncMock(return_value=mock_result),
):
resp = await config_client.post("/api/config/jails/sshd/rollback")
@@ -2228,7 +2228,7 @@ class TestRollbackEndpoint:
message="fail2ban did not come back online.",
)
with patch(
"app.routers.config.jail_config_service._rollback_jail",
"app.routers.jail_config.jail_config_service._rollback_jail",
AsyncMock(return_value=mock_result),
):
resp = await config_client.post("/api/config/jails/sshd/rollback")
@@ -2241,10 +2241,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.jail_config_service import JailNameError
from app.exceptions import JailNameError
with patch(
"app.routers.config.jail_config_service.rollback_jail",
"app.routers.jail_config.jail_config_service.rollback_jail",
AsyncMock(side_effect=JailNameError("bad")),
):
resp = await config_client.post("/api/config/jails/bad/rollback")