from datetime import date, datetime, timezone from fastapi.testclient import TestClient from sqlmodel import Session, delete, func, select from app.core.config import settings from app.models import TerminalMessageRaw from app.mqtt.repository import insert_raw_message def _reset_raw_data(db: Session) -> None: db.execute(delete(TerminalMessageRaw)) db.commit() def _count_raw_rows(db: Session) -> int: statement = select(func.count()).select_from(TerminalMessageRaw) return int(db.exec(statement).one()) def test_list_mqtt_raw_days( client: TestClient, superuser_token_headers: dict[str, str], db: Session ) -> None: _reset_raw_data(db) insert_raw_message( session=db, device_id="device-a", topic="terminal/device-a/raw", payload=b"A1", qos=1, retain=False, received_at=datetime(2026, 3, 10, 8, 0, tzinfo=timezone.utc), ) insert_raw_message( session=db, device_id="device-a", topic="terminal/device-a/raw", payload=b"A2", qos=1, retain=False, received_at=datetime(2026, 3, 10, 21, 0, tzinfo=timezone.utc), ) insert_raw_message( session=db, device_id="device-b", topic="terminal/device-b/raw", payload=b"B1", qos=1, retain=False, received_at=datetime(2026, 3, 11, 9, 0, tzinfo=timezone.utc), ) response = client.get( f"{settings.API_V1_STR}/mqtt-raw/days?skip=0&limit=10", headers=superuser_token_headers, ) assert response.status_code == 200 content = response.json() assert content["count"] == 2 assert content["data"][0]["day"] == "2026-03-11" assert content["data"][0]["message_count"] == 2 assert content["data"][1]["day"] == "2026-03-10" assert content["data"][1]["message_count"] == 1 def test_download_mqtt_raw_by_day_or_time_range( client: TestClient, superuser_token_headers: dict[str, str], db: Session ) -> None: _reset_raw_data(db) target_day = date(2026, 3, 12) insert_raw_message( session=db, device_id="device-a", topic="terminal/device-a/raw", payload=b"EARLY\n", qos=1, retain=False, received_at=datetime(2026, 3, 11, 20, 0, tzinfo=timezone.utc), ) insert_raw_message( session=db, device_id="device-a", topic="terminal/device-a/raw", payload=b"MID\n", qos=1, retain=False, received_at=datetime(2026, 3, 12, 3, 0, tzinfo=timezone.utc), ) insert_raw_message( session=db, device_id="device-a", topic="terminal/device-a/raw", payload=b"LATE\n", qos=1, retain=False, received_at=datetime(2026, 3, 12, 12, 0, tzinfo=timezone.utc), ) insert_raw_message( session=db, device_id="device-a", topic="terminal/device-a/raw", payload=b"NEXT_DAY\n", qos=1, retain=False, received_at=datetime(2026, 3, 12, 18, 0, tzinfo=timezone.utc), ) full_day_response = client.get( f"{settings.API_V1_STR}/mqtt-raw/download", headers=superuser_token_headers, params={"day": target_day.isoformat()}, ) assert full_day_response.status_code == 200 assert full_day_response.content == b"EARLY\nMID\nLATE\n" range_response = client.get( f"{settings.API_V1_STR}/mqtt-raw/download", headers=superuser_token_headers, params={ "day": target_day.isoformat(), "start_seconds": 10 * 3600, "end_seconds": 14 * 3600, }, ) assert range_response.status_code == 200 assert range_response.content == b"MID\n" def test_delete_mqtt_raw_by_day( client: TestClient, superuser_token_headers: dict[str, str], db: Session ) -> None: _reset_raw_data(db) insert_raw_message( session=db, device_id="device-x", topic="terminal/device-x/raw", payload=b"X", qos=1, retain=False, received_at=datetime(2026, 3, 14, 20, 30, tzinfo=timezone.utc), ) insert_raw_message( session=db, device_id="device-a", topic="terminal/device-a/raw", payload=b"A", qos=1, retain=False, received_at=datetime(2026, 3, 15, 1, 0, tzinfo=timezone.utc), ) insert_raw_message( session=db, device_id="device-b", topic="terminal/device-b/raw", payload=b"B", qos=1, retain=False, received_at=datetime(2026, 3, 15, 12, 0, tzinfo=timezone.utc), ) insert_raw_message( session=db, device_id="device-c", topic="terminal/device-c/raw", payload=b"C", qos=1, retain=False, received_at=datetime(2026, 3, 15, 16, 30, tzinfo=timezone.utc), ) response = client.delete( f"{settings.API_V1_STR}/mqtt-raw/day/2026-03-15", headers=superuser_token_headers, ) assert response.status_code == 200 content = response.json() assert content["deleted_count"] == 3 assert _count_raw_rows(db) == 1 def test_delete_all_mqtt_raw_requires_confirmation( client: TestClient, superuser_token_headers: dict[str, str], db: Session ) -> None: _reset_raw_data(db) insert_raw_message( session=db, device_id="device-a", topic="terminal/device-a/raw", payload=b"A", qos=1, retain=False, received_at=datetime(2026, 3, 15, 1, 0, tzinfo=timezone.utc), ) insert_raw_message( session=db, device_id="device-b", topic="terminal/device-b/raw", payload=b"B", qos=1, retain=False, received_at=datetime(2026, 3, 16, 1, 0, tzinfo=timezone.utc), ) reject_response = client.delete( f"{settings.API_V1_STR}/mqtt-raw/all", headers=superuser_token_headers, ) assert reject_response.status_code == 400 assert _count_raw_rows(db) == 2 confirmed_response = client.delete( f"{settings.API_V1_STR}/mqtt-raw/all?confirm=true", headers=superuser_token_headers, ) assert confirmed_response.status_code == 200 content = confirmed_response.json() assert content["deleted_count"] == 2 assert _count_raw_rows(db) == 0