# Backend API Test Guide This directory contains the backend API test suite. The tests use pytest, FastAPI's `TestClient`, and an isolated in-memory SQLite database. The goal is to cover the business-critical API behaviour without relying on MySQL, SMTP, or a running browser. ## How To Run From `backend/`: ```bash pytest pytest --cov=app --cov-report=term-missing ``` From the project root with Docker Compose running: ```bash docker compose exec api pytest docker compose exec api pytest --cov=app --cov-report=term-missing ``` ## Shared Fixtures ### `conftest.py` Sets up the test harness used by every module. What it does: - Provides safe default environment variables before the app imports settings. - Creates an in-memory SQLite database and overrides FastAPI's `get_db` dependency. - Recreates all tables for every test so tests cannot leak state into each other. - Patches SQLite primary-key handling for models that use `BigInteger` ids in production. - Provides `client` for unauthenticated requests and `auth_client` for administrator/operator requests. - Provides reusable PPR payload and factory fixtures. Why it exists: - Keeps API tests fast, deterministic, and independent from Docker MySQL data. - Lets tests exercise the real FastAPI routes, schemas, CRUD calls, and dependency overrides. ## Test Modules ### `test_app_health.py` Covers the simplest application-level endpoints. What it tests: - `/` returns API metadata. - `/health` reports a healthy application and database connection. Why it matters: - These tests catch broken app imports, router setup problems, and database dependency regressions early. ### `test_auth_api.py` Covers authentication and admin user-management routes. What it tests: - Login rejects invalid credentials. - Login returns a bearer token for a valid user. - Admin users can create, list, update, and change passwords for users. - Duplicate users and missing users return the expected errors. Why it matters: - Auth is the gatekeeper for most operational endpoints. - The admin user flow is also a good end-to-end check of password hashing, token creation, CRUD, and journal side effects. ### `test_pprs_api.py` Covers the core PPR lifecycle. What it tests: - PPR routes require authentication where appropriate. - Authenticated users can create, read, update, patch, acknowledge, status-update, soft-delete, and audit PPRs. - List filters work for status, dates, skip, and limit. - Public PPR creation sends email and generates secure edit tokens. - Public edit and cancel token flows work and reject invalid or processed requests. - Activation creates an arrival and pending departure. - Missing PPRs return 404. - Invalid payloads return validation errors. Why it matters: - PPRs are the central workflow in the system. - These tests protect the operational state transitions that drive tower/admin views and audit history. ### `test_public_api.py` Covers public read-only board and lookup endpoints. What it tests: - Public arrivals and departures start empty. - Today's PPRs, local flights, arrivals, and departures appear on public boards. - Old or cancelled records are excluded. - Public airport and aircraft lookups return seeded records. - Short or invalid lookup queries return empty lists. Why it matters: - Public boards and lookup helpers are user-facing and unauthenticated. - These tests check that the public API exposes useful operational information without requiring login. ### `test_flight_strip_apis.py` Covers authenticated flight-strip style CRUD endpoints. What it tests: - Arrival lifecycle: create, list/filter, read, update, land, cancel, and not-found paths. - Landing an arrival promotes a linked pending departure. - Departure lifecycle: create, list/filter, update, takeoff/departure status, cancel, and not-found paths. - Local flight lifecycle: create, list/filter, update, depart, land, special lists, cancel, and not-found paths. - Overflight lifecycle: create, active/today lists, list/filter, update, mark inactive/QSY, cancel, and not-found paths. - Movement records are created for real takeoff, landing, touch-and-go, and overflight events where relevant. Why it matters: - These endpoints represent day-to-day tower strip operations. - They also exercise important CRUD side effects: status timestamps, movements, linked departures, and journal entries. ### `test_circuits_api.py` Covers circuit/touch-and-go records. What it tests: - Circuits can be recorded for local flights. - Circuits can be recorded for arrivals. - Circuit list, lookup-by-flight, lookup-by-arrival, update, and delete work. - Invalid circuit creation requests are rejected when neither or both parent ids are supplied. - Missing circuits return 404. - Recording a circuit creates a touch-and-go movement. Why it matters: - Circuit traffic is a distinct operational pattern and feeds movement logging. - The parent-id validation prevents ambiguous audit/movement records. ### `test_movements_api.py` Covers movement listing, context lookup, and bulk paper-strip logging. What it tests: - Movement list filters and single-record reads. - Bulk movement context suggests matching PPRs and existing movements. - Bulk logging can create and update PPR-linked arrivals. - Bulk logging can create unmatched arrival and departure records. - Bulk logging handles local flight strips with takeoff, landing, duration, and circuits. - Bulk logging handles overflight strips and updates existing overflight records. - Invalid bulk-log requests return helpful 400 errors. Why it matters: - Bulk movement logging is one of the densest workflows in the API. - These tests protect the behaviour that translates paper-strip data into PPR, arrival, departure, local flight, overflight, movement, and journal records. ### `test_drone_requests_api.py` Covers drone flight request workflows. What it tests: - Public drone request creation generates references/tokens and sends confirmation email. - Public edit and cancel token flows work. - Processed drone requests cannot be edited or cancelled publicly. - Authenticated users can list, read, update, status-update, comment on, and audit drone requests. - Missing records and invalid payloads return expected errors. Why it matters: - Drone requests are a newer workflow with public and authenticated surfaces. - The tests protect email notification, public token, status, comment, and journal behaviour. ### `test_public_book_api.py` Covers the optional public booking portal. What it tests: - Public booking rejects requests when disabled. - Public local flight booking creates a public-submitted local flight. - Public circuit recording creates a circuit and touch-and-go movement. - Public departure and arrival booking create public-submitted records with pilot emails. - Invalid public booking payloads return validation errors. Why it matters: - Public booking is controlled by configuration and should be safe to disable. - When enabled, it creates operational records without authentication, so validation and submitted-via metadata matter. ### `test_journal_api.py` Covers generic audit/journal endpoints. What it tests: - Journal search filters by date, entity type, entity id, and user. - Invalid entity types are rejected. - User journal and entity journal endpoints return entries and summary counts. Why it matters: - The journal is the audit trail across PPRs, flights, users, drone requests, and movements. - These tests make sure audit entries remain queryable as the system grows. ## Current Scope The suite intentionally focuses on API behaviour, local WebSocket broadcast behaviour, and database side effects. It does not deeply test: - Full browser WebSocket lifecycle. - Real SMTP delivery. - Browser UI behaviour. - Every branch of low-level validators or helper functions. Those areas are better handled with focused unit tests or E2E tests later.