server-up/tests/test_jobs.py
Ramon c658418b10
All checks were successful
Deploy server-up (dev) / deploy (push) Successful in 6m16s
fix(netwerk): koppel niet langer de database aan het gedeelde netwerk
add_shared_network hing elke service van een stack aan het gedeelde netwerk.
Eén druk op 'koppelen' maakte daarmee de database van die app bereikbaar voor
elke andere gekoppelde app — en niet elk sjabloon zet daar een wachtwoord op.

- Standaard gaan alleen services mee die geen database, cache of zoekindex
  zijn; brokers als mosquitto en rabbitmq blijven wel deelbaar.
- Per onderdeel te kiezen in de stap 'Verbinden'; de keuze staat in
  .serverup.json en geldt ook bij een volgende wijziging.
- mongodump/mongorestore sturen geen inloggegevens meer mee bij een database
  zonder authenticatie; die dump mislukte altijd.
- Joblogs worden bewaard in SU_JOBS (standaard /data/jobs) en teruggelezen na
  een herstart; een afgekapte taak meldt dat in plaats van 'unknown'.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H9Vcwu7owJZ3nj5dCf4VFT
2026-08-06 23:14:24 +02:00

91 lines
3.1 KiB
Python

"""Het joblog moet een herstart overleven.
Jobs stonden alleen in het geheugen. Juist bij het bijwerken herstart de
container middenin de taak, en dan gaf `/api/jobs/<id>` alleen nog "unknown":
de interface bleef pollen zonder ooit te vertellen hoe het afliep.
"""
import json
import sys
from pathlib import Path
WORTEL = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(WORTEL / "server-up"))
def _job_met_regels(jobs, tag="backup:web", regels=("bezig", "klaar")):
jid, q = jobs.create(tag)
for r in regels:
jobs.log(q, "dim", r)
jobs.stream(jid) # regels uit de queue in de job trekken
return jid
def test_afgeronde_job_blijft_op_schijf_staan(env):
from core import jobs
jid = _job_met_regels(jobs)
jobs.finish(jid, "done")
bestand = Path(env["data"]) / "jobs" / f"{jid}.json"
assert bestand.is_file()
bewaard = json.loads(bestand.read_text())
assert bewaard["status"] == "done"
assert [r["text"] for r in bewaard["lines"]] == ["bezig", "klaar"]
def test_log_blijft_leesbaar_nadat_de_job_uit_het_geheugen_is(env):
"""Na de TTL ruimt Server Up jobs op; het log hoort dan nog te bestaan."""
from core import jobs
jid = _job_met_regels(jobs)
jobs.finish(jid, "done")
jobs._jobs.clear() # zoals _cleanup() na een uur doet
d = jobs.stream(jid)
assert d["status"] == "done"
assert [r["text"] for r in d["lines"]] == ["bezig", "klaar"]
assert jobs.stream(jid, offset=1)["lines"][0]["text"] == "klaar"
def test_onderbroken_job_wordt_als_zodanig_teruggelezen(env):
"""Een taak die liep toen de container omviel mag niet als 'running'
terugkomen: dan blijft de interface eeuwig wachten."""
from core import jobs
# Geen finish(): de job loopt nog. Het pollen van de interface schrijft
# tussentijds weg, en dat is precies wat er van hem overblijft.
jid = _job_met_regels(jobs, regels=("backup wordt gemaakt",))
assert (Path(env["data"]) / "jobs" / f"{jid}.json").is_file()
jobs._jobs.clear() # de herstart
assert jobs.herstel() >= 1
d = jobs.stream(jid)
assert d["status"] == "error"
tekst = " ".join(r["text"] for r in d["lines"])
assert "backup wordt gemaakt" in tekst
assert "herstart" in tekst
def test_onbekende_job_blijft_onbekend(env):
from core import jobs
assert jobs.stream("bestaatniet")["status"] == "unknown"
def test_er_blijven_niet_eindeloos_joblogs_liggen(env):
from core import jobs
for i in range(jobs._BEWAAR + 5):
jobs.finish(_job_met_regels(jobs, tag=f"taak-{i}"), "done")
bestanden = list((Path(env["data"]) / "jobs").glob("*.json"))
assert len(bestanden) <= jobs._BEWAAR
def test_joblog_van_de_api_komt_ook_van_schijf(client, env):
"""De route zelf moet het bewaarde log teruggeven, niet alleen de module."""
from conftest import login
from core import jobs
login(client)
jid = _job_met_regels(jobs, regels=("stap 1",))
jobs.finish(jid, "error")
jobs._jobs.clear()
d = client.get(f"/api/jobs/{jid}").get_json()
assert d["status"] == "error"
assert d["lines"][0]["text"] == "stap 1"