Erstumsetzung: OAMC Turnierauswertung (AP 0–7, 9)
* Datenmodell + Alembic-Initialmigration (Plan §4), Seed Saison 2026 * Wertungs-Engine (Plan §3.3), regelbasiert je Kategorie/Saison - Abnahmetest gegen die Ergebnisliste 2026-05-31 * Meisterschaftsberechnung mit Streichresultaten + Tie-Break (PLATZHALTER-Punktetabelle, O-1 offen) * Ingest-API (idempotent, dry_run) inkl. Excel-Leser und Fahrer-Matching/Merge * Zeitmessungs-Endpoint (Batch, idempotent, unzugeordnet/unplausibel) + SSE-Anzeige - Mess-Pi-Client bewusst NICHT enthalten (docs/zeitmessung-endpoint.md) * Frontend: öffentliche Seiten + internes Backend (Jinja2/HTMX, kein Build) * Auslieferung: Docker (multi-arch) + docker-compose sowie Debian-Paket/APT-Repo * 57 Tests grün gegen echte PostgreSQL-Testdatenbank Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
"""Rauchtest der serverseitig gerenderten Seiten (AP 6/7)."""
|
||||
|
||||
from datetime import date
|
||||
|
||||
from oamc.seeds import seed_saison_2026
|
||||
from tests import factories as f
|
||||
|
||||
|
||||
def test_startseite_rendert(client):
|
||||
r = client.get("/")
|
||||
assert r.status_code == 200
|
||||
assert "Motorrad-Turniere" in r.text
|
||||
|
||||
|
||||
def test_robots_txt_sperrt_fahrerprofile(client):
|
||||
r = client.get("/robots.txt")
|
||||
assert "Disallow: /fahrer/" in r.text
|
||||
|
||||
|
||||
def test_termine_ics(client):
|
||||
seed_saison_2026(client.db)
|
||||
f.veranstaltung(client.db, titel="Doppelturnier", datum=date(2026, 5, 31))
|
||||
r = client.get("/termine.ics")
|
||||
assert r.status_code == 200
|
||||
assert r.headers["content-type"].startswith("text/calendar")
|
||||
assert "BEGIN:VCALENDAR" in r.text
|
||||
|
||||
|
||||
def test_ergebnisliste_und_csv(client):
|
||||
db = client.db
|
||||
seed_saison_2026(db)
|
||||
t = f.turnier(db)
|
||||
k = f.klasse(db, "J 3")
|
||||
fahrer = f.fahrer(db, "Freund", "Philipp", 2014)
|
||||
s = f.start(db, t, fahrer, k, startnummer=7)
|
||||
e = f.ergebnis(db, s, zeit="136.88", fehler=0)
|
||||
e.gesamt = 0
|
||||
e.platzierung = 1
|
||||
db.flush()
|
||||
|
||||
html = client.get(f"/ergebnisse/turnier/{t.id}")
|
||||
assert html.status_code == 200
|
||||
assert "Freund Philipp" in html.text
|
||||
|
||||
csv = client.get(f"/ergebnisse/turnier/{t.id}.csv")
|
||||
assert csv.status_code == 200
|
||||
assert "Freund Philipp" in csv.text
|
||||
assert csv.headers["content-disposition"].endswith('.csv"')
|
||||
|
||||
|
||||
def test_fahrerprofil_hat_noindex(client):
|
||||
db = client.db
|
||||
seed_saison_2026(db)
|
||||
fahrer = f.fahrer(db, "Muster", "Max", 2014)
|
||||
db.flush()
|
||||
r = client.get(f"/fahrer/{fahrer.id}")
|
||||
assert r.status_code == 200
|
||||
assert 'name="robots" content="noindex"' in r.text
|
||||
|
||||
|
||||
def test_intern_ohne_login_leitet_um(client):
|
||||
r = client.get("/intern", follow_redirects=False)
|
||||
assert r.status_code in (307, 401)
|
||||
|
||||
|
||||
def test_login_flow(client):
|
||||
from oamc.models import Benutzer
|
||||
from oamc.models.enums import BenutzerRolle
|
||||
from oamc.security.passwoerter import hash_passwort
|
||||
|
||||
client.db.add(
|
||||
Benutzer(
|
||||
benutzername="tester",
|
||||
anzeigename="Tester",
|
||||
passwort_hash=hash_passwort("geheim123"),
|
||||
rolle=BenutzerRolle.AUSWERTER,
|
||||
)
|
||||
)
|
||||
client.db.flush()
|
||||
r = client.post(
|
||||
"/intern/login",
|
||||
data={"benutzername": "tester", "passwort": "geheim123"},
|
||||
follow_redirects=False,
|
||||
)
|
||||
assert r.status_code == 303
|
||||
assert "oamc_session" in r.cookies
|
||||
Reference in New Issue
Block a user