import json from datetime import date from conftest import login_ready, new_user def _setup(admin): acc = admin.post("/api/accounts", json={"name": "Exp", "currency": "EUR"}).json() admin.post("/api/transactions", json={ "type": "expense", "date": str(date.today()), "account_id": acc["id"], "amount_cents": 4200, "payee": "Testladen", "description": "Etwas", }) return acc def test_export_transactions_csv(admin): _setup(admin) r = admin.get("/api/export/transactions.csv") assert r.status_code == 200 assert "text/csv" in r.headers["content-type"] body = r.content.decode("utf-8-sig") assert "Datum;Typ;Konto" in body.splitlines()[0] assert "Testladen" in body def test_export_transactions_json(admin): _setup(admin) r = admin.get("/api/export/transactions.json") assert r.status_code == 200 data = json.loads(r.content) assert any(t["payee"] == "Testladen" for t in data) def test_export_all_json(admin): _setup(admin) r = admin.get("/api/export/all.json") assert r.status_code == 200 data = json.loads(r.content) assert data["app"] == "Certain Finance" assert len(data["accounts"]) >= 1 assert len(data["transactions"]) >= 1 def test_db_backup_admin_only(admin): # Admin darf. r = admin.get("/api/backup/db") assert r.status_code == 200 assert r.content[:16].startswith(b"SQLite format 3") # Normaler Nutzer darf nicht. other, _ = login_ready(*new_user(admin)) assert other.get("/api/backup/db").status_code == 403 # ...aber seinen eigenen Export schon (leer). assert other.get("/api/export/all.json").status_code == 200 def test_jede_nutzertabelle_ist_im_backup_beruecksichtigt(): """Neue Tabellen dürfen nicht stillschweigend aus dem Backup fallen. Sieben Tabellen sind genau so entstanden: angelegt, migriert, benutzt – und in ``backup_data`` nie eingetragen. Aufgefallen wäre das erst beim Wiedereinspielen, also im schlechtesten Moment. Dieser Test zwingt jede künftige Tabelle mit ``owner_id`` zu einer bewussten Entscheidung: entweder sichern oder hier begründet ausnehmen. """ from app.models import Base from app.services import backup_data gesichert = { spec.model.__tablename__ for liste in (backup_data.USER_TABLES, backup_data.SYSTEM_USER_TABLES, backup_data.GLOBAL_TABLES) for spec in liste } # Bewusst ausgenommen – die Begründung steht in backup_data.py. ausgenommen = {"mail_sources", "mail_senders", "pending_uploads"} fehlend = sorted( m.class_.__tablename__ for m in Base.registry.mappers if "owner_id" in m.class_.__table__.columns and m.class_.__tablename__ not in gesichert and m.class_.__tablename__ not in ausgenommen ) assert not fehlend, ( f"Diese Tabellen gehören dem Nutzer, stehen aber in keiner Backup-Liste: " f"{fehlend}. Entweder in USER_TABLES aufnehmen oder oben begründet ausnehmen." )