release: bump version to 0.48.0
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
from unittest.mock import AsyncMock
|
||||
from httpx import ASGITransport, AsyncClient
|
||||
|
||||
from app.api.v1.datasource_config import get_ai_provider_client
|
||||
from app.core.websocket import broadcaster as broadcaster_module
|
||||
from app.core.security import get_current_user
|
||||
from app.core.target_schema_registry import get_target_schema, list_target_schemas
|
||||
from app.main import app
|
||||
from app.models.user import User
|
||||
from app.models.datasource_config import DataSourceConfig
|
||||
from app.services import custom_datasource_runtime
|
||||
from app.services.custom_datasource_runtime import run_mapped_websocket_config
|
||||
from app.services.datasource_mapping import execute_mapping, persist_mapped_records, redact_for_llm
|
||||
|
||||
|
||||
@@ -106,6 +111,130 @@ async def test_persist_mapped_records_writes_generic_records():
|
||||
assert db.added[0].extra_data["mapping_version"] == 3
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_persist_mapped_vessel_records_writes_raw_and_broadcasts(monkeypatch):
|
||||
record_observation = AsyncMock(return_value=object())
|
||||
update_health = AsyncMock()
|
||||
broadcast_custom = AsyncMock()
|
||||
monkeypatch.setattr(
|
||||
"app.services.vessel_ais_aggregation.record_vessel_ais_observation",
|
||||
record_observation,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"app.services.vessel_ais_aggregation.update_ais_source_health",
|
||||
update_health,
|
||||
)
|
||||
monkeypatch.setattr(broadcaster_module, "broadcast_custom", broadcast_custom)
|
||||
|
||||
class FakeDB:
|
||||
def __init__(self):
|
||||
self.committed = False
|
||||
|
||||
async def commit(self):
|
||||
self.committed = True
|
||||
|
||||
db = FakeDB()
|
||||
|
||||
count = await persist_mapped_records(
|
||||
db,
|
||||
datasource_name="mock_ais_ws",
|
||||
datasource_config_id=42,
|
||||
target_schema="vessel_ais",
|
||||
records=[
|
||||
{
|
||||
"mmsi": 999000001,
|
||||
"lat": 31.2,
|
||||
"lon": 121.4,
|
||||
"name": "MOCK VESSEL 001",
|
||||
"received_at": "2026-05-01T00:00:00Z",
|
||||
}
|
||||
],
|
||||
mapping_version=1,
|
||||
delivery_mode="realtime_stream",
|
||||
transport="websocket",
|
||||
)
|
||||
|
||||
assert count == 1
|
||||
assert db.committed is True
|
||||
record_observation.assert_awaited_once()
|
||||
assert record_observation.await_args.kwargs["source"] == "mock_ais_ws"
|
||||
assert record_observation.await_args.kwargs["delivery_mode"] == "realtime_stream"
|
||||
assert record_observation.await_args.kwargs["transport"] == "websocket"
|
||||
update_health.assert_awaited_once()
|
||||
broadcast_custom.assert_awaited_once()
|
||||
assert broadcast_custom.await_args.args[0] == "vessels"
|
||||
assert broadcast_custom.await_args.args[1]["vessels"][0]["mmsi_display"] == "999000001"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_custom_websocket_runner_maps_and_persists_vessel_records(monkeypatch):
|
||||
mapping = SimpleNamespace(
|
||||
id=7,
|
||||
version=2,
|
||||
target_schema="vessel_ais",
|
||||
mapping_json={
|
||||
"source": {"items_path": "$"},
|
||||
"fields": {
|
||||
"mmsi": {"path": "$.mmsi", "type": "integer"},
|
||||
"lat": {"path": "$.lat", "type": "float"},
|
||||
"lon": {"path": "$.lon", "type": "float"},
|
||||
"name": {"path": "$.name", "type": "string"},
|
||||
"received_at": {"path": "$.received_at", "type": "datetime"},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
class FakeResult:
|
||||
def scalar_one_or_none(self):
|
||||
return mapping
|
||||
|
||||
class FakeDB:
|
||||
async def execute(self, _stmt):
|
||||
return FakeResult()
|
||||
|
||||
class FakeWebSocket:
|
||||
async def __aenter__(self):
|
||||
return self
|
||||
|
||||
async def __aexit__(self, *_args):
|
||||
return None
|
||||
|
||||
async def send(self, _message):
|
||||
return None
|
||||
|
||||
async def recv(self):
|
||||
return (
|
||||
'{"type":"vessel","data":{"mmsi":"999000001","name":"MOCK VESSEL 001",'
|
||||
'"lat":31.2,"lon":121.4,"received_at":"2026-05-01T00:00:00Z"}}'
|
||||
)
|
||||
|
||||
persist = AsyncMock(return_value=1)
|
||||
monkeypatch.setattr(custom_datasource_runtime, "_connect_websocket", AsyncMock(return_value=FakeWebSocket()))
|
||||
monkeypatch.setattr(custom_datasource_runtime, "persist_mapped_records", persist)
|
||||
|
||||
result = await run_mapped_websocket_config(
|
||||
FakeDB(),
|
||||
DataSourceConfig(
|
||||
id=42,
|
||||
name="mock_ais_ws",
|
||||
source_type="websocket",
|
||||
endpoint="ws://localhost:8787/ais",
|
||||
auth_type="none",
|
||||
headers={},
|
||||
config={"ws_message_path": "$.data", "debug_max_messages": 1},
|
||||
),
|
||||
)
|
||||
|
||||
assert result["status"] == "success"
|
||||
assert result["messages_seen"] == 1
|
||||
assert result["written_count"] == 1
|
||||
persist.assert_awaited_once()
|
||||
assert persist.await_args.kwargs["datasource_name"] == "mock_ais_ws"
|
||||
assert persist.await_args.kwargs["records"][0]["mmsi"] == 999000001
|
||||
assert persist.await_args.kwargs["delivery_mode"] == "realtime_stream"
|
||||
assert persist.await_args.kwargs["transport"] == "websocket"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mapping_preview_api_uses_deterministic_engine():
|
||||
def override_get_current_user():
|
||||
|
||||
Reference in New Issue
Block a user