mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-07-06 12:28:05 +02:00
af9b3d08cc
Add Telegram OSINT with hourly incremental t.me scraping, metro geocoding separate from news centroids, threat-intercept popup UI with inline media, and HTML markers above alert boxes so pins stay clickable. Expose GFW_API_TOKEN in onboarding and Settings Maritime; harden GFW/CCTV/geo fetchers. Port Osiris- derived recon, SCM, entity graph, malware/cyber feeds, sanctions, and submarine cable layers with tests and documentation. Co-authored-by: Cursor <cursoragent@cursor.com>
165 lines
6.4 KiB
Python
165 lines
6.4 KiB
Python
from types import SimpleNamespace
|
|
|
|
|
|
def test_fetch_fishing_activity_paginates(monkeypatch):
|
|
from services.fetchers import geo
|
|
from services.fetchers._store import latest_data
|
|
|
|
original = list(latest_data.get("fishing_activity") or [])
|
|
requests: list[str] = []
|
|
|
|
def fake_fetch(url, timeout=30, headers=None):
|
|
requests.append(url)
|
|
if "offset=0" in url:
|
|
payload = {
|
|
"entries": [
|
|
{
|
|
"id": "evt-1",
|
|
"position": {"lat": 10.0, "lon": 20.0},
|
|
"event": {"duration": 3600},
|
|
"vessel": {"id": "v-1", "ssvid": "ssvid-1", "name": "Alpha", "flag": "PA"},
|
|
},
|
|
{
|
|
"id": "evt-2",
|
|
"position": {"lat": 11.0, "lon": 21.0},
|
|
"event": {"duration": 7200},
|
|
"vessel": {"id": "v-2", "ssvid": "ssvid-2", "name": "Bravo", "flag": "US"},
|
|
},
|
|
],
|
|
"nextOffset": 2,
|
|
}
|
|
elif "offset=2" in url:
|
|
payload = {
|
|
"entries": [
|
|
{
|
|
"id": "evt-3",
|
|
"position": {"lat": 12.0, "lon": 22.0},
|
|
"event": {"duration": 1800},
|
|
"vessel": {"id": "v-3", "ssvid": "ssvid-3", "name": "Charlie", "flag": "GB"},
|
|
}
|
|
]
|
|
}
|
|
else:
|
|
payload = {"entries": []}
|
|
return SimpleNamespace(status_code=200, json=lambda: payload)
|
|
|
|
monkeypatch.setenv("GFW_API_TOKEN", "test-token")
|
|
monkeypatch.setenv("GFW_EVENTS_PAGE_SIZE", "2")
|
|
monkeypatch.setattr("services.fetchers._store.is_any_active", lambda *args: True)
|
|
monkeypatch.setattr(geo, "fetch_with_curl", fake_fetch)
|
|
monkeypatch.setattr(geo, "_mark_fresh", lambda *args, **kwargs: None)
|
|
|
|
try:
|
|
geo.fetch_fishing_activity()
|
|
assert len(latest_data["fishing_activity"]) == 3
|
|
assert latest_data["fishing_activity"][2]["id"] == "evt-3"
|
|
assert any("offset=0" in url for url in requests)
|
|
assert any("offset=2" in url for url in requests)
|
|
finally:
|
|
latest_data["fishing_activity"] = original
|
|
|
|
|
|
def test_fetch_fishing_activity_dedupes_to_latest_event_per_vessel(monkeypatch):
|
|
from services.fetchers import geo
|
|
from services.fetchers._store import latest_data
|
|
|
|
original = list(latest_data.get("fishing_activity") or [])
|
|
|
|
def fake_fetch(url, timeout=30, headers=None):
|
|
payload = {
|
|
"entries": [
|
|
{
|
|
"id": "evt-old",
|
|
"type": "fishing",
|
|
"start": "2026-04-01T00:00:00.000Z",
|
|
"end": "2026-04-02T00:00:00.000Z",
|
|
"position": {"lat": 10.0, "lon": 20.0},
|
|
"event": {"duration": 3600},
|
|
"vessel": {"id": "v-1", "ssvid": "ssvid-1", "name": "Alpha", "flag": "PA"},
|
|
},
|
|
{
|
|
"id": "evt-new",
|
|
"type": "fishing",
|
|
"start": "2026-04-03T00:00:00.000Z",
|
|
"end": "2026-04-04T00:00:00.000Z",
|
|
"position": {"lat": 11.0, "lon": 21.0},
|
|
"event": {"duration": 7200},
|
|
"vessel": {"id": "v-1", "ssvid": "ssvid-1", "name": "Alpha", "flag": "PA"},
|
|
},
|
|
{
|
|
"id": "evt-other",
|
|
"type": "fishing",
|
|
"start": "2026-04-03T00:00:00.000Z",
|
|
"end": "2026-04-03T12:00:00.000Z",
|
|
"position": {"lat": 12.0, "lon": 22.0},
|
|
"event": {"duration": 1800},
|
|
"vessel": {"id": "v-2", "ssvid": "ssvid-2", "name": "Bravo", "flag": "US"},
|
|
},
|
|
]
|
|
}
|
|
return SimpleNamespace(status_code=200, json=lambda: payload)
|
|
|
|
monkeypatch.setenv("GFW_API_TOKEN", "test-token")
|
|
monkeypatch.setenv("GFW_EVENTS_PAGE_SIZE", "500")
|
|
monkeypatch.setattr("services.fetchers._store.is_any_active", lambda *args: True)
|
|
monkeypatch.setattr(geo, "fetch_with_curl", fake_fetch)
|
|
monkeypatch.setattr(geo, "_mark_fresh", lambda *args, **kwargs: None)
|
|
|
|
try:
|
|
geo.fetch_fishing_activity()
|
|
assert len(latest_data["fishing_activity"]) == 2
|
|
assert latest_data["fishing_activity"][0]["id"] == "evt-new"
|
|
assert latest_data["fishing_activity"][0]["event_count"] == 2
|
|
assert latest_data["fishing_activity"][0]["vessel_ssvid"] == "ssvid-1"
|
|
finally:
|
|
latest_data["fishing_activity"] = original
|
|
|
|
|
|
def test_fetch_fishing_activity_respects_max_pages(monkeypatch):
|
|
from services.fetchers import geo
|
|
from services.fetchers._store import latest_data
|
|
|
|
original = list(latest_data.get("fishing_activity") or [])
|
|
requests: list[str] = []
|
|
|
|
def fake_fetch(url, timeout=30, headers=None):
|
|
requests.append(url)
|
|
offset = 0
|
|
if "offset=500" in url:
|
|
offset = 500
|
|
payload = {
|
|
"total": 5000,
|
|
"entries": [
|
|
{
|
|
"id": f"evt-{offset + i}",
|
|
"position": {"lat": 10.0 + i, "lon": 20.0 + i},
|
|
"event": {"duration": 3600},
|
|
"vessel": {
|
|
"id": f"v-{offset + i}",
|
|
"ssvid": f"ssvid-{offset + i}",
|
|
"name": f"Vessel-{offset + i}",
|
|
"flag": "US",
|
|
},
|
|
}
|
|
for i in range(500)
|
|
],
|
|
"nextOffset": offset + 500,
|
|
}
|
|
return SimpleNamespace(status_code=200, json=lambda p=payload: p)
|
|
|
|
monkeypatch.setenv("GFW_API_TOKEN", "test-token")
|
|
monkeypatch.setenv("GFW_EVENTS_PAGE_SIZE", "500")
|
|
monkeypatch.setenv("GFW_EVENTS_MAX_PAGES", "2")
|
|
monkeypatch.setattr("services.fetchers._store.is_any_active", lambda *args: True)
|
|
monkeypatch.setattr(geo, "fetch_with_curl", fake_fetch)
|
|
monkeypatch.setattr(geo, "_mark_fresh", lambda *args, **kwargs: None)
|
|
monkeypatch.setattr(geo, "_last_fishing_fetch_ts", 0.0)
|
|
|
|
try:
|
|
geo.fetch_fishing_activity()
|
|
assert len(latest_data["fishing_activity"]) == 1000
|
|
assert len(requests) == 2
|
|
assert all("offset=0" in url or "offset=500" in url for url in requests)
|
|
finally:
|
|
latest_data["fishing_activity"] = original
|