106 lines
3.2 KiB
Python
106 lines
3.2 KiB
Python
from datetime import datetime, timedelta, timezone
|
|
|
|
import pytest
|
|
from httpx import ASGITransport, AsyncClient
|
|
|
|
from app.api.v1.visualization import convert_vessels_to_geojson
|
|
from app.db.session import get_db
|
|
from app.main import app
|
|
from app.models.vessel import VesselPosition, VesselStatic
|
|
from app.services.collectors.vessel_ais import VesselAISCollector
|
|
|
|
|
|
def test_vessel_collector_transforms_barentswatch_like_records():
|
|
collector = VesselAISCollector()
|
|
records = collector.transform(
|
|
[
|
|
{
|
|
"mmsi": "257123000",
|
|
"lat": "59.91",
|
|
"lon": "10.73",
|
|
"sog": 12.4,
|
|
"cog": 214,
|
|
"nav_status": 0,
|
|
"shipType": 70,
|
|
"name": "OSLO TRADER",
|
|
},
|
|
{"mmsi": "bad", "lat": 120, "lon": 10},
|
|
]
|
|
)
|
|
|
|
assert len(records) == 1
|
|
assert records[0]["mmsi"] == 257123000
|
|
assert records[0]["vessel_type_name"] == "Cargo"
|
|
assert records[0]["lat"] == pytest.approx(59.91)
|
|
|
|
|
|
def test_convert_vessels_to_geojson():
|
|
position = VesselPosition(
|
|
mmsi=257123000,
|
|
lat=59.91,
|
|
lon=10.73,
|
|
sog=12.4,
|
|
cog=214,
|
|
heading=215,
|
|
nav_status=0,
|
|
received_at=datetime(2026, 4, 28, 1, 0, tzinfo=timezone.utc),
|
|
)
|
|
static = VesselStatic(
|
|
mmsi=257123000,
|
|
name="OSLO TRADER",
|
|
vessel_type=70,
|
|
vessel_type_name="Cargo",
|
|
flag="NO",
|
|
length=185,
|
|
)
|
|
|
|
payload = convert_vessels_to_geojson([(position, static)])
|
|
|
|
assert payload["type"] == "FeatureCollection"
|
|
assert payload["features"][0]["geometry"]["coordinates"] == [10.73, 59.91]
|
|
assert payload["features"][0]["properties"]["mmsi"] == 257123000
|
|
assert payload["features"][0]["properties"]["vessel_type_name"] == "Cargo"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_vessels_geojson_endpoint_filters_type_and_bbox():
|
|
now = datetime(2026, 4, 28, 1, 0, tzinfo=timezone.utc)
|
|
rows = [
|
|
(
|
|
VesselPosition(mmsi=1, lat=59.9, lon=10.7, received_at=now),
|
|
VesselStatic(mmsi=1, name="Cargo Ship", vessel_type=70, vessel_type_name="Cargo"),
|
|
),
|
|
(
|
|
VesselPosition(mmsi=2, lat=60.3, lon=5.3, received_at=now - timedelta(minutes=1)),
|
|
VesselStatic(mmsi=2, name="Passenger Ship", vessel_type=60, vessel_type_name="Passenger"),
|
|
),
|
|
]
|
|
|
|
class _Result:
|
|
def all(self):
|
|
return rows
|
|
|
|
class _FakeSession:
|
|
async def execute(self, _query):
|
|
return _Result()
|
|
|
|
async def override_get_db():
|
|
yield _FakeSession()
|
|
|
|
app.dependency_overrides[get_db] = override_get_db
|
|
transport = ASGITransport(app=app)
|
|
try:
|
|
async with AsyncClient(transport=transport, base_url="http://test") as client:
|
|
response = await client.get(
|
|
"/api/v1/visualization/geo/vessels",
|
|
params={"bbox": "0,50,20,70", "type": "cargo"},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["count"] == 1
|
|
assert data["features"][0]["properties"]["name"] == "Cargo Ship"
|
|
assert data["stats"]["by_type"]["Cargo"] == 1
|
|
finally:
|
|
app.dependency_overrides.clear()
|