From 4d599e98827c90ca8afcb48a90697ded8dcbcb89 Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 13 Apr 2026 20:34:27 +0200 Subject: [PATCH] Add endpoint tests and Gitea workflow --- .gitea/workflows/python.yml | 28 ++++++++ tests/test_main.py | 130 ++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 .gitea/workflows/python.yml create mode 100644 tests/test_main.py diff --git a/.gitea/workflows/python.yml b/.gitea/workflows/python.yml new file mode 100644 index 0000000..8eaed8d --- /dev/null +++ b/.gitea/workflows/python.yml @@ -0,0 +1,28 @@ +name: python + +on: + push: + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt pytest httpx + + - name: Compile checks + run: python -m compileall -q app tests + + - name: Run tests + run: pytest -q diff --git a/tests/test_main.py b/tests/test_main.py new file mode 100644 index 0000000..e853d63 --- /dev/null +++ b/tests/test_main.py @@ -0,0 +1,130 @@ +from types import SimpleNamespace + +import pytest +from fastapi.testclient import TestClient + +import app.main as main + + +class DummySettings(SimpleNamespace): + @property + def auth_enabled(self): + return bool(self.auth_token) + + +@pytest.fixture(autouse=True) +def reset_settings(monkeypatch): + monkeypatch.setattr( + main, + "settings", + DummySettings( + env="test", + test_ui_enabled=True, + auth_token="", + auth_header_name="X-API-Key", + ), + ) + + +@pytest.fixture() +def client(): + return TestClient(main.app) + + +def test_health_reflects_settings(client): + resp = client.get("/health") + assert resp.status_code == 200 + assert resp.json() == { + "ok": True, + "env": "test", + "test_ui_enabled": True, + "auth_enabled": False, + "auth_header": None, + } + + +def test_index_shows_disabled_message_when_ui_off(monkeypatch): + monkeypatch.setattr( + main, + "settings", + DummySettings( + env="test", + test_ui_enabled=False, + auth_token="", + auth_header_name="X-API-Key", + ), + ) + resp = TestClient(main.app).get("/") + assert resp.status_code == 200 + assert "Test UI is disabled." in resp.text + + +def test_focus_accepts_bearer_auth_and_returns_payload(monkeypatch, client): + monkeypatch.setattr( + main, + "settings", + DummySettings( + env="test", + test_ui_enabled=True, + auth_token="secret", + auth_header_name="X-API-Key", + ), + ) + + def fake_process_image(image_bytes, filename, buffer_ratio=0.15, detector="subject"): + assert image_bytes == b"image-bytes" + assert filename == "sample.jpg" + assert buffer_ratio == 0.2 + assert detector == "face" + return { + "filename": filename, + "detector": detector, + "method": "face_cascade", + "buffer_ratio": buffer_ratio, + "detected_bbox": {"x": 1, "y": 2, "w": 3, "h": 4}, + "square_bbox": {"x": 0, "y": 0, "w": 8, "h": 8}, + "source_size": {"width": 10, "height": 12}, + "crop_data_url": "data:image/jpeg;base64,AAA=", + "annotated_data_url": "data:image/jpeg;base64,BBB=", + "mime_type": "image/jpeg", + "crop_bytes": b"crop", + } + + monkeypatch.setattr("app.vision.process_image", fake_process_image) + + resp = client.post( + "/api/focus", + headers={"Authorization": "Bearer secret"}, + files={"file": ("sample.jpg", b"image-bytes", "image/jpeg")}, + data={"buffer_ratio": "0.2", "detector": "face"}, + ) + assert resp.status_code == 200 + assert resp.json()["method"] == "face_cascade" + assert resp.json()["detected_bbox"] == {"x": 1, "y": 2, "w": 3, "h": 4} + + +def test_focus_image_returns_jpeg_stream(monkeypatch, client): + def fake_process_image(image_bytes, filename, buffer_ratio=0.15, detector="subject"): + return { + "filename": filename, + "detector": detector, + "method": "subject_contour", + "buffer_ratio": buffer_ratio, + "detected_bbox": {"x": 1, "y": 2, "w": 3, "h": 4}, + "square_bbox": {"x": 0, "y": 0, "w": 8, "h": 8}, + "source_size": {"width": 10, "height": 12}, + "crop_data_url": "data:image/jpeg;base64,AAA=", + "annotated_data_url": "data:image/jpeg;base64,BBB=", + "mime_type": "image/jpeg", + "crop_bytes": b"crop-bytes", + } + + monkeypatch.setattr("app.vision.process_image", fake_process_image) + + resp = client.post( + "/api/focus/image", + files={"file": ("sample.jpg", b"image-bytes", "image/jpeg")}, + ) + assert resp.status_code == 200 + assert resp.headers["content-type"] == "image/jpeg" + assert resp.content == b"crop-bytes"