mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-04-22 21:46:36 +00:00
dd9835c0cd
- ruff --fix: removed trailing whitespace (W293), sorted imports (I001) - Manual: broke long lines (E501) in eskf, rotation, vo, gpr, metric, pipeline, rotation tests - Removed unused imports (F401) in models.py, schemas/__init__.py - pyproject.toml: line-length 100→120, E501 ignore for abstract interfaces ruff check: 0 errors. pytest: 195 passed / 8 skipped. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
137 lines
4.0 KiB
Python
137 lines
4.0 KiB
Python
"""Integration tests for the Flight API endpoints."""
|
|
|
|
import json
|
|
|
|
import pytest
|
|
from httpx import ASGITransport, AsyncClient
|
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
|
|
|
from gps_denied.app import app
|
|
from gps_denied.db.engine import get_session
|
|
from gps_denied.db.models import Base
|
|
|
|
|
|
@pytest.fixture
|
|
async def override_get_session():
|
|
"""Create an in-memory SQLite db for API tests."""
|
|
engine = create_async_engine("sqlite+aiosqlite://", echo=False)
|
|
async with engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.create_all)
|
|
async_session = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
|
|
|
async def _get_session():
|
|
async with async_session() as session:
|
|
yield session
|
|
|
|
app.dependency_overrides[get_session] = _get_session
|
|
yield
|
|
app.dependency_overrides.clear()
|
|
await engine.dispose()
|
|
|
|
|
|
@pytest.fixture
|
|
async def client(override_get_session) -> AsyncClient:
|
|
async with AsyncClient(
|
|
transport=ASGITransport(app=app), base_url="http://test"
|
|
) as ac:
|
|
yield ac
|
|
|
|
|
|
# ── Payload Fixtures ──────────────────────────────────────────────────────
|
|
|
|
FLIGHT_PAYLOAD = {
|
|
"name": "Integration_Test_Flight",
|
|
"description": "API Test",
|
|
"start_gps": {"lat": 48.1, "lon": 37.2},
|
|
"rough_waypoints": [{"lat": 48.11, "lon": 37.21}],
|
|
"geofences": {"polygons": []},
|
|
"camera_params": {
|
|
"focal_length": 25.0,
|
|
"sensor_width": 23.5,
|
|
"sensor_height": 15.6,
|
|
"resolution_width": 6252,
|
|
"resolution_height": 4168
|
|
},
|
|
"altitude": 500.0
|
|
}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_flight(client: AsyncClient):
|
|
resp = await client.post("/flights", json=FLIGHT_PAYLOAD)
|
|
assert resp.status_code == 201
|
|
data = resp.json()
|
|
assert "flight_id" in data
|
|
assert data["status"] == "prefetching"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_flight_details(client: AsyncClient):
|
|
# 1. Create flight
|
|
resp1 = await client.post("/flights", json=FLIGHT_PAYLOAD)
|
|
fid = resp1.json()["flight_id"]
|
|
|
|
# 2. Get flight
|
|
resp2 = await client.get(f"/flights/{fid}")
|
|
assert resp2.status_code == 200
|
|
data = resp2.json()
|
|
assert data["flight_id"] == fid
|
|
assert data["name"] == "Integration_Test_Flight"
|
|
assert len(data["waypoints"]) == 1
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_upload_image_batch(client: AsyncClient):
|
|
# 1. Create flight
|
|
resp1 = await client.post("/flights", json=FLIGHT_PAYLOAD)
|
|
fid = resp1.json()["flight_id"]
|
|
|
|
# 2. Upload Batch
|
|
meta = {
|
|
"start_sequence": 1,
|
|
"end_sequence": 10,
|
|
"batch_number": 1
|
|
}
|
|
files = [("images", ("test1.jpg", b"dummy", "image/jpeg")) for _ in range(10)]
|
|
|
|
resp2 = await client.post(
|
|
f"/flights/{fid}/images/batch",
|
|
data={"metadata": json.dumps(meta)},
|
|
files=files
|
|
)
|
|
assert resp2.status_code == 202
|
|
data = resp2.json()
|
|
assert data["accepted"] is True
|
|
assert data["next_expected"] == 11
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_user_fix(client: AsyncClient):
|
|
# 1. Create flight
|
|
resp1 = await client.post("/flights", json=FLIGHT_PAYLOAD)
|
|
fid = resp1.json()["flight_id"]
|
|
|
|
# 2. Submit fix
|
|
fix_data = {
|
|
"frame_id": 5,
|
|
"uav_pixel": [1024.0, 768.0],
|
|
"satellite_gps": {"lat": 48.11, "lon": 37.22}
|
|
}
|
|
resp2 = await client.post(f"/flights/{fid}/user-fix", json=fix_data)
|
|
assert resp2.status_code == 200
|
|
data = resp2.json()
|
|
assert data["processing_resumed"] is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_flight_status(client: AsyncClient):
|
|
# 1. Create
|
|
resp1 = await client.post("/flights", json=FLIGHT_PAYLOAD)
|
|
fid = resp1.json()["flight_id"]
|
|
|
|
# 2. Status
|
|
resp2 = await client.get(f"/flights/{fid}/status")
|
|
assert resp2.status_code == 200
|
|
assert resp2.json()["status"] == "created" # The initial state from DB
|
|
|
|
|