diff --git a/infra/run-domain-check.sh b/infra/run-domain-check.sh index 329209e..2dde71c 100755 --- a/infra/run-domain-check.sh +++ b/infra/run-domain-check.sh @@ -157,4 +157,80 @@ for _ in $(seq 1 15); do done [ -n "$gone" ] || { echo "FAIL — Beoordelen task for $reg_id2 still active after withdrawal" >&2; docker logs "$dom" 2>&1 | tail -15 >&2; exit 1; } echo "OK — withdrawal cancelled the Beoordelen task; the registratie process ended (ingetrokken)" + +# ── S-14: escalation. A third registration parks at Beoordelen. We fire its 14-day boundary timer +# early via Flowable's management API (the timer job is moved to executable and run), which routes a +# parallel token to the BeoordelingEscaleren external task. The domain's escalation worker acquires +# it and reassigns the still-open Beoordelen task from the behandelaar group to teamlead (ADR-0015). ─ +echo ">> submitting a third registration to escalate" +loc3="$(docker run --rm --network "$net" curlimages/curl:latest \ + -fsS -D - -o /dev/null -X POST "http://$dom_ip:8080/registrations" \ + -H 'Content-Type: application/json' -d '{"bsn":"123456782"}' \ + | sed -n 's/\r$//; s/^[Ll]ocation: //p' | head -1)" +[ -n "$loc3" ] || { echo "FAIL — third POST /registrations returned no Location" >&2; exit 1; } +reg_id3="${loc3##*/}" +echo ">> third registration $reg_id3" + +# Extracts " " for a registration from a task-query response on stdin. +task_and_pid_for_reg() { REG_ID="$1" python3 -c "import os,sys,json +try: + d=json.load(sys.stdin) +except Exception: + d={} +rid=os.environ['REG_ID'] +t=next((t for t in (d.get('data') or []) + if any(v.get('name')=='registrationId' and v.get('value')==rid for v in (t.get('variables') or []))), None) +print(f\"{t['id']} {t['processInstanceId']}\" if t else '')"; } + +# The candidate groups on a task (space-separated, sorted) from a runtime identitylinks response. +candidate_groups() { python3 -c "import sys,json +try: + links=json.load(sys.stdin) +except Exception: + links=[] +print(' '.join(sorted(l.get('group') or '' for l in links if l.get('type')=='candidate' and l.get('group'))))"; } + +# The first job id in a management jobs/timer-jobs response on stdin. +first_job_id() { python3 -c "import sys,json +try: + d=json.load(sys.stdin) +except Exception: + d={} +print(((d.get('data') or [{}])[0]).get('id',''))"; } + +echo ">> polling Flowable for its Beoordelen task" +task_id3=""; pid3="" +for _ in $(seq 1 30); do + resp="$(flcurl -X POST "$fl_base/query/tasks" -H 'Content-Type: application/json' -d "$query" 2>/dev/null || true)" + read -r task_id3 pid3 <<<"$(printf '%s' "$resp" | task_and_pid_for_reg "$reg_id3")" + [ -n "$task_id3" ] && break + sleep 2 +done +[ -n "$task_id3" ] || { echo "FAIL — no Beoordelen task appeared for registration $reg_id3" >&2; docker logs "$dom" 2>&1 | tail -15 >&2; exit 1; } +echo ">> Beoordelen task $task_id3 (instance $pid3) is waiting for the behandelaar" + +echo ">> asserting the task starts out claimable by the behandelaar group" +before="$(flcurl "$fl_base/runtime/tasks/$task_id3/identitylinks" | candidate_groups)" +[ "$before" = "behandelaar" ] || { echo "FAIL — expected candidate group 'behandelaar', got '$before'" >&2; exit 1; } + +echo ">> firing the 14-day boundary timer early via the management API" +timer_id="$(flcurl "$fl_base/management/timer-jobs?processInstanceId=$pid3" | first_job_id)" +[ -n "$timer_id" ] || { echo "FAIL — no timer job found for instance $pid3" >&2; exit 1; } +# Move the timer job to an executable async job, then execute it — firing the non-interrupting event +# without depending on the async executor's schedule. +flcurl -X POST "$fl_base/management/timer-jobs/$timer_id" -H 'Content-Type: application/json' -d '{"action":"move"}' >/dev/null +async_id="$(flcurl "$fl_base/management/jobs?processInstanceId=$pid3" | first_job_id)" +[ -n "$async_id" ] || { echo "FAIL — timer job did not become an executable job" >&2; exit 1; } +flcurl -X POST "$fl_base/management/jobs/$async_id" -H 'Content-Type: application/json' -d '{"action":"execute"}' >/dev/null +echo ">> timer fired; the BeoordelingEscaleren token is parked for the domain worker" + +echo ">> polling until the escalation worker reassigns the beoordeling to the teamlead" +escalated="" +for _ in $(seq 1 30); do + groups="$(flcurl "$fl_base/runtime/tasks/$task_id3/identitylinks" 2>/dev/null | candidate_groups || true)" + [ "$groups" = "teamlead" ] && { escalated=1; break; } + sleep 2 +done +[ -n "$escalated" ] || { echo "FAIL — Beoordelen task not reassigned to teamlead (candidate groups: '$groups')" >&2; docker logs "$dom" 2>&1 | tail -15 >&2; exit 1; } +echo "OK — the 14-day timer escalated the still-open Beoordelen task to the teamlead" exit 0