refactor: complete Task 2/3 geo decouple + exceptions centralization; mark as done
This commit is contained in:
@@ -154,7 +154,7 @@ class TestListBansHappyPath:
|
||||
async def test_returns_bans_in_range(self, f2b_db_path: str) -> None:
|
||||
"""Only bans within the selected range are returned."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans("/fake/sock", "24h")
|
||||
@@ -166,7 +166,7 @@ class TestListBansHappyPath:
|
||||
async def test_results_sorted_newest_first(self, f2b_db_path: str) -> None:
|
||||
"""Items are ordered by ``banned_at`` descending (newest first)."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans("/fake/sock", "24h")
|
||||
@@ -177,7 +177,7 @@ class TestListBansHappyPath:
|
||||
async def test_ban_fields_present(self, f2b_db_path: str) -> None:
|
||||
"""Each item contains ip, jail, banned_at, ban_count."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans("/fake/sock", "24h")
|
||||
@@ -191,7 +191,7 @@ class TestListBansHappyPath:
|
||||
async def test_service_extracted_from_first_match(self, f2b_db_path: str) -> None:
|
||||
"""``service`` field is the first element of ``data.matches``."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans("/fake/sock", "24h")
|
||||
@@ -203,7 +203,7 @@ class TestListBansHappyPath:
|
||||
async def test_service_is_none_when_no_matches(self, f2b_db_path: str) -> None:
|
||||
"""``service`` is ``None`` when the ban has no stored matches."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
):
|
||||
# Use 7d to include the older ban with no matches.
|
||||
@@ -215,7 +215,7 @@ class TestListBansHappyPath:
|
||||
async def test_empty_db_returns_zero(self, empty_f2b_db_path: str) -> None:
|
||||
"""When no bans exist the result has total=0 and no items."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=empty_f2b_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans("/fake/sock", "24h")
|
||||
@@ -226,7 +226,7 @@ class TestListBansHappyPath:
|
||||
async def test_365d_range_includes_old_bans(self, f2b_db_path: str) -> None:
|
||||
"""The ``365d`` range includes bans that are 2 days old."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans("/fake/sock", "365d")
|
||||
@@ -246,7 +246,7 @@ class TestListBansGeoEnrichment:
|
||||
self, f2b_db_path: str
|
||||
) -> None:
|
||||
"""Geo fields are populated when an enricher returns data."""
|
||||
from app.services.geo_service import GeoInfo
|
||||
from app.models.geo import GeoInfo
|
||||
|
||||
async def fake_enricher(ip: str) -> GeoInfo:
|
||||
return GeoInfo(
|
||||
@@ -257,7 +257,7 @@ class TestListBansGeoEnrichment:
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans(
|
||||
@@ -278,7 +278,7 @@ class TestListBansGeoEnrichment:
|
||||
raise RuntimeError("geo service down")
|
||||
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans(
|
||||
@@ -304,25 +304,27 @@ class TestListBansBatchGeoEnrichment:
|
||||
"""Geo fields are populated via lookup_batch when http_session is given."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from app.services.geo_service import GeoInfo
|
||||
from app.models.geo import GeoInfo
|
||||
|
||||
fake_session = MagicMock()
|
||||
fake_geo_map = {
|
||||
"1.2.3.4": GeoInfo(country_code="DE", country_name="Germany", asn="AS3320", org="Deutsche Telekom"),
|
||||
"5.6.7.8": GeoInfo(country_code="US", country_name="United States", asn="AS15169", org="Google"),
|
||||
}
|
||||
fake_geo_batch = AsyncMock(return_value=fake_geo_map)
|
||||
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
), patch(
|
||||
"app.services.geo_service.lookup_batch",
|
||||
new=AsyncMock(return_value=fake_geo_map),
|
||||
):
|
||||
result = await ban_service.list_bans(
|
||||
"/fake/sock", "24h", http_session=fake_session
|
||||
"/fake/sock",
|
||||
"24h",
|
||||
http_session=fake_session,
|
||||
geo_batch_lookup=fake_geo_batch,
|
||||
)
|
||||
|
||||
fake_geo_batch.assert_awaited_once_with(["1.2.3.4", "5.6.7.8"], fake_session, db=None)
|
||||
assert result.total == 2
|
||||
de_item = next(i for i in result.items if i.ip == "1.2.3.4")
|
||||
us_item = next(i for i in result.items if i.ip == "5.6.7.8")
|
||||
@@ -339,15 +341,17 @@ class TestListBansBatchGeoEnrichment:
|
||||
|
||||
fake_session = MagicMock()
|
||||
|
||||
failing_geo_batch = AsyncMock(side_effect=RuntimeError("batch geo down"))
|
||||
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
), patch(
|
||||
"app.services.geo_service.lookup_batch",
|
||||
new=AsyncMock(side_effect=RuntimeError("batch geo down")),
|
||||
):
|
||||
result = await ban_service.list_bans(
|
||||
"/fake/sock", "24h", http_session=fake_session
|
||||
"/fake/sock",
|
||||
"24h",
|
||||
http_session=fake_session,
|
||||
geo_batch_lookup=failing_geo_batch,
|
||||
)
|
||||
|
||||
assert result.total == 2
|
||||
@@ -360,28 +364,27 @@ class TestListBansBatchGeoEnrichment:
|
||||
"""When both http_session and geo_enricher are provided, batch wins."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from app.services.geo_service import GeoInfo
|
||||
from app.models.geo import GeoInfo
|
||||
|
||||
fake_session = MagicMock()
|
||||
fake_geo_map = {
|
||||
"1.2.3.4": GeoInfo(country_code="DE", country_name="Germany", asn=None, org=None),
|
||||
"5.6.7.8": GeoInfo(country_code="DE", country_name="Germany", asn=None, org=None),
|
||||
}
|
||||
fake_geo_batch = AsyncMock(return_value=fake_geo_map)
|
||||
|
||||
async def enricher_should_not_be_called(ip: str) -> GeoInfo:
|
||||
raise AssertionError(f"geo_enricher was called for {ip!r} — should not happen")
|
||||
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
), patch(
|
||||
"app.services.geo_service.lookup_batch",
|
||||
new=AsyncMock(return_value=fake_geo_map),
|
||||
):
|
||||
result = await ban_service.list_bans(
|
||||
"/fake/sock",
|
||||
"24h",
|
||||
http_session=fake_session,
|
||||
geo_batch_lookup=fake_geo_batch,
|
||||
geo_enricher=enricher_should_not_be_called,
|
||||
)
|
||||
|
||||
@@ -401,7 +404,7 @@ class TestListBansPagination:
|
||||
async def test_page_size_respected(self, f2b_db_path: str) -> None:
|
||||
"""``page_size=1`` returns at most one item."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans("/fake/sock", "7d", page_size=1)
|
||||
@@ -412,7 +415,7 @@ class TestListBansPagination:
|
||||
async def test_page_2_returns_remaining_items(self, f2b_db_path: str) -> None:
|
||||
"""The second page returns items not on the first page."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
):
|
||||
page1 = await ban_service.list_bans("/fake/sock", "7d", page=1, page_size=1)
|
||||
@@ -426,7 +429,7 @@ class TestListBansPagination:
|
||||
) -> None:
|
||||
"""``total`` reports all matching records regardless of pagination."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans("/fake/sock", "7d", page_size=1)
|
||||
@@ -447,7 +450,7 @@ class TestBanOriginDerivation:
|
||||
) -> None:
|
||||
"""Bans from ``blocklist-import`` jail carry ``origin == "blocklist"``."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans("/fake/sock", "24h")
|
||||
@@ -461,7 +464,7 @@ class TestBanOriginDerivation:
|
||||
) -> None:
|
||||
"""Bans from organic jails (sshd, nginx, …) carry ``origin == "selfblock"``."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans("/fake/sock", "24h")
|
||||
@@ -476,7 +479,7 @@ class TestBanOriginDerivation:
|
||||
) -> None:
|
||||
"""Every returned item has an ``origin`` field with a valid value."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans("/fake/sock", "24h")
|
||||
@@ -489,7 +492,7 @@ class TestBanOriginDerivation:
|
||||
) -> None:
|
||||
"""``bans_by_country`` also derives origin correctly for blocklist bans."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.bans_by_country("/fake/sock", "24h")
|
||||
@@ -503,7 +506,7 @@ class TestBanOriginDerivation:
|
||||
) -> None:
|
||||
"""``bans_by_country`` derives origin correctly for organic jails."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.bans_by_country("/fake/sock", "24h")
|
||||
@@ -527,7 +530,7 @@ class TestOriginFilter:
|
||||
) -> None:
|
||||
"""``origin='blocklist'`` returns only blocklist-import jail bans."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans(
|
||||
@@ -544,7 +547,7 @@ class TestOriginFilter:
|
||||
) -> None:
|
||||
"""``origin='selfblock'`` excludes the blocklist-import jail."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans(
|
||||
@@ -562,7 +565,7 @@ class TestOriginFilter:
|
||||
) -> None:
|
||||
"""``origin=None`` applies no jail restriction — all bans returned."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.list_bans("/fake/sock", "24h", origin=None)
|
||||
@@ -574,7 +577,7 @@ class TestOriginFilter:
|
||||
) -> None:
|
||||
"""``bans_by_country`` with ``origin='blocklist'`` counts only blocklist bans."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.bans_by_country(
|
||||
@@ -589,7 +592,7 @@ class TestOriginFilter:
|
||||
) -> None:
|
||||
"""``bans_by_country`` with ``origin='selfblock'`` excludes blocklist jails."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.bans_by_country(
|
||||
@@ -604,7 +607,7 @@ class TestOriginFilter:
|
||||
) -> None:
|
||||
"""``bans_by_country`` with ``origin=None`` returns all bans."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.bans_by_country(
|
||||
@@ -644,7 +647,7 @@ class TestBansbyCountryBackground:
|
||||
|
||||
with (
|
||||
patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
),
|
||||
patch(
|
||||
@@ -652,8 +655,13 @@ class TestBansbyCountryBackground:
|
||||
) as mock_create_task,
|
||||
):
|
||||
mock_session = AsyncMock()
|
||||
mock_batch = AsyncMock(return_value={})
|
||||
result = await ban_service.bans_by_country(
|
||||
"/fake/sock", "24h", http_session=mock_session
|
||||
"/fake/sock",
|
||||
"24h",
|
||||
http_session=mock_session,
|
||||
geo_cache_lookup=geo_service.lookup_cached_only,
|
||||
geo_batch_lookup=mock_batch,
|
||||
)
|
||||
|
||||
# All countries resolved from cache — no background task needed.
|
||||
@@ -674,7 +682,7 @@ class TestBansbyCountryBackground:
|
||||
|
||||
with (
|
||||
patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
),
|
||||
patch(
|
||||
@@ -682,8 +690,13 @@ class TestBansbyCountryBackground:
|
||||
) as mock_create_task,
|
||||
):
|
||||
mock_session = AsyncMock()
|
||||
mock_batch = AsyncMock(return_value={})
|
||||
result = await ban_service.bans_by_country(
|
||||
"/fake/sock", "24h", http_session=mock_session
|
||||
"/fake/sock",
|
||||
"24h",
|
||||
http_session=mock_session,
|
||||
geo_cache_lookup=geo_service.lookup_cached_only,
|
||||
geo_batch_lookup=mock_batch,
|
||||
)
|
||||
|
||||
# Background task must have been scheduled for uncached IPs.
|
||||
@@ -701,7 +714,7 @@ class TestBansbyCountryBackground:
|
||||
|
||||
with (
|
||||
patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
),
|
||||
patch(
|
||||
@@ -727,7 +740,7 @@ class TestBanTrend:
|
||||
async def test_24h_returns_24_buckets(self, empty_f2b_db_path: str) -> None:
|
||||
"""``range_='24h'`` always yields exactly 24 buckets."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=empty_f2b_db_path),
|
||||
):
|
||||
result = await ban_service.ban_trend("/fake/sock", "24h")
|
||||
@@ -738,7 +751,7 @@ class TestBanTrend:
|
||||
async def test_7d_returns_28_buckets(self, empty_f2b_db_path: str) -> None:
|
||||
"""``range_='7d'`` yields 28 six-hour buckets."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=empty_f2b_db_path),
|
||||
):
|
||||
result = await ban_service.ban_trend("/fake/sock", "7d")
|
||||
@@ -749,7 +762,7 @@ class TestBanTrend:
|
||||
async def test_30d_returns_30_buckets(self, empty_f2b_db_path: str) -> None:
|
||||
"""``range_='30d'`` yields 30 daily buckets."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=empty_f2b_db_path),
|
||||
):
|
||||
result = await ban_service.ban_trend("/fake/sock", "30d")
|
||||
@@ -760,7 +773,7 @@ class TestBanTrend:
|
||||
async def test_365d_bucket_size_label(self, empty_f2b_db_path: str) -> None:
|
||||
"""``range_='365d'`` uses '7d' as the bucket size label."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=empty_f2b_db_path),
|
||||
):
|
||||
result = await ban_service.ban_trend("/fake/sock", "365d")
|
||||
@@ -771,7 +784,7 @@ class TestBanTrend:
|
||||
async def test_empty_db_all_buckets_zero(self, empty_f2b_db_path: str) -> None:
|
||||
"""All bucket counts are zero when the database has no bans."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=empty_f2b_db_path),
|
||||
):
|
||||
result = await ban_service.ban_trend("/fake/sock", "24h")
|
||||
@@ -781,7 +794,7 @@ class TestBanTrend:
|
||||
async def test_buckets_are_time_ordered(self, empty_f2b_db_path: str) -> None:
|
||||
"""Buckets are ordered chronologically (ascending timestamps)."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=empty_f2b_db_path),
|
||||
):
|
||||
result = await ban_service.ban_trend("/fake/sock", "7d")
|
||||
@@ -804,7 +817,7 @@ class TestBanTrend:
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=path),
|
||||
):
|
||||
result = await ban_service.ban_trend("/fake/sock", "24h")
|
||||
@@ -828,7 +841,7 @@ class TestBanTrend:
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=path),
|
||||
):
|
||||
result = await ban_service.ban_trend(
|
||||
@@ -854,7 +867,7 @@ class TestBanTrend:
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=path),
|
||||
):
|
||||
result = await ban_service.ban_trend(
|
||||
@@ -868,7 +881,7 @@ class TestBanTrend:
|
||||
from datetime import datetime
|
||||
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=empty_f2b_db_path),
|
||||
):
|
||||
result = await ban_service.ban_trend("/fake/sock", "24h")
|
||||
@@ -904,7 +917,7 @@ class TestBansByJail:
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=path),
|
||||
):
|
||||
result = await ban_service.bans_by_jail("/fake/sock", "24h")
|
||||
@@ -931,7 +944,7 @@ class TestBansByJail:
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=path),
|
||||
):
|
||||
result = await ban_service.bans_by_jail("/fake/sock", "24h")
|
||||
@@ -942,7 +955,7 @@ class TestBansByJail:
|
||||
async def test_empty_db_returns_empty_list(self, empty_f2b_db_path: str) -> None:
|
||||
"""An empty database returns an empty jails list with total zero."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=empty_f2b_db_path),
|
||||
):
|
||||
result = await ban_service.bans_by_jail("/fake/sock", "24h")
|
||||
@@ -954,7 +967,7 @@ class TestBansByJail:
|
||||
"""Bans older than the time window are not counted."""
|
||||
# f2b_db_path has one ban from _TWO_DAYS_AGO, which is outside "24h".
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=f2b_db_path),
|
||||
):
|
||||
result = await ban_service.bans_by_jail("/fake/sock", "24h")
|
||||
@@ -965,7 +978,7 @@ class TestBansByJail:
|
||||
async def test_origin_filter_blocklist(self, mixed_origin_db_path: str) -> None:
|
||||
"""``origin='blocklist'`` returns only the blocklist-import jail."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.bans_by_jail(
|
||||
@@ -979,7 +992,7 @@ class TestBansByJail:
|
||||
async def test_origin_filter_selfblock(self, mixed_origin_db_path: str) -> None:
|
||||
"""``origin='selfblock'`` excludes the blocklist-import jail."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.bans_by_jail(
|
||||
@@ -995,7 +1008,7 @@ class TestBansByJail:
|
||||
) -> None:
|
||||
"""``origin=None`` returns bans from all jails."""
|
||||
with patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=mixed_origin_db_path),
|
||||
):
|
||||
result = await ban_service.bans_by_jail(
|
||||
@@ -1023,7 +1036,7 @@ class TestBansByJail:
|
||||
|
||||
with (
|
||||
patch(
|
||||
"app.services.ban_service._get_fail2ban_db_path",
|
||||
"app.services.ban_service.get_fail2ban_db_path",
|
||||
new=AsyncMock(return_value=path),
|
||||
),
|
||||
patch("app.services.ban_service.log") as mock_log,
|
||||
|
||||
Reference in New Issue
Block a user