from collections.abc import Generator from typing import Any import pytest from flask.testing import FlaskClient from src.app import app, db @pytest.fixture def client() -> Generator[FlaskClient, Any, Any]: app.config["TESTING"] = True app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:" with app.app_context(): db.create_all() yield app.test_client() db.drop_all() def test_heartbeat_status_code(client: FlaskClient) -> None: response = client.get("/heartbeat") assert response.status_code == 200 def test_camera_start(client: FlaskClient) -> None: response = client.post("/camera/start") assert response.status_code == 200 assert response.get_json()["status"] in ("started", "already_running") def test_camera_stop(client: FlaskClient) -> None: client.post("/camera/start") response = client.post("/camera/stop") assert response.status_code == 200 assert response.get_json()["status"] in ("stopped", "already_stopped") def test_double_start_is_idempotent(client): client.post("/camera/start") res = client.post("/camera/start") assert res.get_json()["status"] == "already_running" def test_camera_status(client: FlaskClient) -> None: response = client.get("/camera/status") assert response.status_code == 200 data = response.get_json() assert "running" in data assert "ready" in data assert "updated_at" in data def test_camera_log(client): client.post("/camera/start") client.post("/camera/stop") res = client.get("/camera/log") assert res.status_code == 200 events = res.get_json() assert len(events) == 2 assert events[0]["action"] == "stop" # most recent first assert events[1]["action"] == "start" assert "ip_address" in events[0] assert "timestamp" in events[0] def test_hls_404_when_not_running(client: FlaskClient) -> None: response = client.get("/camera/hls/stream.m3u8") assert response.status_code == 404 def test_index_page(client: FlaskClient) -> None: response = client.get("/") assert response.status_code == 200 assert b"Pi Camera" in response.data