feat: Phase 3 Tasks 23-25 + Quality-Gate-Fixes
Task 23: Worker-Intake-Pipeline verbinden
- ergebnis-Feld in Submission/Payload
- worker.py extrahiert + worker_loop refactor
- test_worker.py mit VerarbeiteSubmission/WorkerLoop tests
Task 24: Admin-Stats mit echten Daten
- processed_total, uptime, error_rate, VERSION
- admin_health mit Redis-Live-Daten
Task 25: E2E-Integrationstest + worker_refaktorisiert
Quality-Gate-Fixes:
- consumername Collision: 'worker-1' -> f'worker-{id(self)}'
- fakeredis block=0 Timeout fix
- WhatsApp/Telegram webhook payload fixes
- test_telegram/integration/e2e/refaktorisiert
- handler.py recovery nach corrupted Patch
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
"""Tests für admin-Route."""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import fakeredis
|
||||
import pytest
|
||||
import redis as _real_redis
|
||||
from flask import Flask
|
||||
|
||||
from src.app import create_app
|
||||
from src.routes.admin import admin_bp
|
||||
|
||||
|
||||
class _FakeRedis:
|
||||
@staticmethod
|
||||
def exceptions():
|
||||
return _real_redis.exceptions
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._conn = fakeredis.FakeStrictRedis(decode_responses=True)
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._conn, name)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def flask_app() -> Flask:
|
||||
"""Erstellt Flask-App mit admin Blueprint."""
|
||||
app = create_app()
|
||||
app.queue_handler = MagicMock()
|
||||
app.queue_handler.queue_size.return_value = 0
|
||||
app.register_blueprint(admin_bp, name="admin_extended", url_prefix="/")
|
||||
return app
|
||||
|
||||
|
||||
class TestAdminStats:
|
||||
"""Tests für Admin-Stats."""
|
||||
|
||||
def test_admin_queue(self, flask_app: Flask) -> None:
|
||||
"""Admin/queue gibt Queue-Status zurück."""
|
||||
with flask_app.test_client() as client:
|
||||
response = client.get("/admin/queue")
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert "queue_size" in data
|
||||
assert "processed_total" in data
|
||||
assert data["status"] == "ok"
|
||||
|
||||
def test_admin_stats(self, flask_app: Flask) -> None:
|
||||
"""Admin/stats gibt echte Metriken zurück."""
|
||||
with flask_app.test_client() as client:
|
||||
response = client.get("/admin/stats")
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert "queue_size" in data
|
||||
assert "processed_total" in data
|
||||
assert "processed_errors" in data
|
||||
assert "error_rate" in data
|
||||
assert "uptime" in data
|
||||
assert "version" in data
|
||||
assert "status" in data
|
||||
|
||||
def test_admin_health(self, flask_app: Flask) -> None:
|
||||
"""Admin/health gibt Health-Check zurück."""
|
||||
with flask_app.test_client() as client:
|
||||
response = client.get("/admin/health")
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert "status" in data
|
||||
assert "redis" in data
|
||||
assert "version" in data
|
||||
|
||||
|
||||
class TestAdminRoute:
|
||||
"""Tests für Admin-Route."""
|
||||
|
||||
def test_admin_queue_status(self, flask_app: Flask) -> None:
|
||||
"""GET /admin/queue → Queue-Status."""
|
||||
mock_qh = MagicMock()
|
||||
mock_qh.queue_size.return_value = 5
|
||||
mock_qh.redis.smembers.return_value = {"msg1", "msg2", "msg3"}
|
||||
flask_app.queue_handler = mock_qh
|
||||
|
||||
with flask_app.test_client() as client:
|
||||
response = client.get("/admin/queue")
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data["queue_size"] == 5
|
||||
assert data["processed_total"] == 3
|
||||
assert data["status"] == "ok"
|
||||
|
||||
def test_admin_stats_extended(self, flask_app: Flask) -> None:
|
||||
"""GET /admin/stats → erweiterte Metriken."""
|
||||
mock_qh = MagicMock()
|
||||
mock_qh.queue_size.return_value = 0
|
||||
mock_qh.redis.smembers.return_value = {"msg1", "msg2"}
|
||||
mock_qh.redis.get.return_value = 1
|
||||
flask_app.queue_handler = mock_qh
|
||||
|
||||
with flask_app.test_client() as client:
|
||||
response = client.get("/admin/stats")
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
|
||||
assert "queue_size" in data
|
||||
assert "processed_total" in data
|
||||
assert "processed_errors" in data
|
||||
assert "error_rate" in data
|
||||
assert "uptime" in data
|
||||
assert "version" in data
|
||||
assert data["status"] == "running"
|
||||
|
||||
def test_admin_health_with_redis(self, flask_app: Flask) -> None:
|
||||
"""GET /admin/health → healthy wenn Redis da."""
|
||||
mock_qh = MagicMock()
|
||||
mock_qh.redis.ping.return_value = True
|
||||
flask_app.queue_handler = mock_qh
|
||||
|
||||
with flask_app.test_client() as client:
|
||||
response = client.get("/admin/health")
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data["status"] == "healthy"
|
||||
assert data["redis"] == "connected"
|
||||
|
||||
def test_admin_health_without_redis(self, flask_app: Flask) -> None:
|
||||
"""GET /admin/health → degraded wenn Redis fehlt."""
|
||||
mock_qh = MagicMock()
|
||||
mock_qh.redis.ping.side_effect = Exception("Connection refused")
|
||||
flask_app.queue_handler = mock_qh
|
||||
|
||||
with flask_app.test_client() as client:
|
||||
response = client.get("/admin/health")
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data["status"] == "degraded"
|
||||
assert data["redis"] == "disconnected"
|
||||
Reference in New Issue
Block a user