Rauchtest: der Lebenszyklus, einmal wirklich ausgefuehrt -- und die fuenfte Fundstelle
rehire_employee war seit dem 17.09. bei jedem Aufruf kaputt, und keine Pruefung konnte das bemerken: die Selbstpruefungen der Migrationen lesen den Text der Funktionen, die Unit-Tests laufen ohne Datenbank, und die Integrationstests haben keinen Bestand, gegen den sie liefen. db/tests/rauchtest.sql schliesst die Luecke -- es ruft die Funktionen auf, gegen die echte Datenbank, in der Reihenfolge des Lebenszyklus: anlegen, versetzen, befoerdern, vormerken, austreten, wiedereintreten. Zwei Eigenschaften, ohne die es gefaehrlich waere. Es laeuft als Anwendungsrolle statt als Superuser -- sonst bewiese es nur, dass die Funktionen fuer niemanden gehen, der sie benutzt. Und es rollt am Ende zurueck, mit einer Zaehlung danach, die das belegt: beim Test vom 29.09. sind reale Personen auf Testplanstellen umgezogen und dort geblieben. Beim Schreiben fiel die fuenfte Stelle mit dem Paar aus Schliessen und Einfuegen auf: terminate_employee. Wer heute eingestellt und heute wieder ausgetragen wird -- ohne den Grund "No Show" --, lief in chk_assignment_range. Die No-Show-Haelfte derselben Funktion macht es laengst richtig und erklaert auch, warum; es galt nur fuer genau einen Austrittsgrund.
This commit is contained in:
76
db/migrations/20260929220000_austritt_am_selben_tag.sql
Normal file
76
db/migrations/20260929220000_austritt_am_selben_tag.sql
Normal file
@@ -0,0 +1,76 @@
|
||||
-- Austritt am Tag, an dem die Besetzung begann
|
||||
--
|
||||
-- Die fünfte Stelle mit demselben Paar aus Schliessen und Einfügen, gefunden
|
||||
-- beim Schreiben des Rauchtests: terminate_employee schliesst die Besetzung auf
|
||||
-- das Austrittsdatum. Wer heute eingestellt und heute wieder ausgetragen wird —
|
||||
-- ohne den Grund „No Show" —, läuft damit in chk_assignment_range.
|
||||
--
|
||||
-- Die No-Show-Hälfte derselben Funktion macht es längst richtig und erklärt
|
||||
-- auch, warum: eine Besetzung von null Tagen hat nicht stattgefunden, also wird
|
||||
-- sie entfernt statt geschlossen. Nur galt das bisher für genau einen
|
||||
-- Austrittsgrund. Ein Eintritt am selben Tag zurückgenommen, aber mit
|
||||
-- „Einvernehmliche Auflösung" statt „No Show", scheiterte an der rohen
|
||||
-- Datenbankmeldung.
|
||||
--
|
||||
-- Damit sind es fünf: hire/rehire brauchen es nicht (sie legen an, sie
|
||||
-- schliessen nicht), transfer_employee, promote_employee und die beiden Zweige
|
||||
-- des Nachtlaufs stehen seit 20260929180000, terminate_employee kommt hier
|
||||
-- dazu.
|
||||
|
||||
do $migration$
|
||||
declare
|
||||
v_alt constant text := $anker$update position_assignments set valid_to = v_exit$anker$;
|
||||
v_neu constant text := $anker$delete from position_assignments
|
||||
where employee_id = v_employee_id and valid_to is null and valid_from >= v_exit;
|
||||
update position_assignments set valid_to = v_exit$anker$;
|
||||
v_def text;
|
||||
v_anzahl int;
|
||||
begin
|
||||
select pg_get_functiondef(p.oid) into v_def
|
||||
from pg_proc p join pg_namespace n on n.oid = p.pronamespace
|
||||
where n.nspname = 'public' and p.proname = 'terminate_employee' and p.prokind = 'f';
|
||||
if v_def is null then raise exception 'terminate_employee ist nicht vorhanden.'; end if;
|
||||
|
||||
v_anzahl := (length(v_def) - length(replace(v_def, v_alt, ''))) / length(v_alt);
|
||||
if v_anzahl <> 1 then
|
||||
raise exception 'Der Anker in terminate_employee kommt % mal vor, erwartet einmal.', v_anzahl;
|
||||
end if;
|
||||
|
||||
execute replace(v_def, v_alt, v_neu);
|
||||
end
|
||||
$migration$;
|
||||
|
||||
|
||||
-- Selbstprüfung: das Neue und alles, was an dieser Funktion schon einmal
|
||||
-- verlorengegangen ist. Die Anmerkung ist beim Umbau auf No-Show einmal
|
||||
-- stillschweigend verschwunden und fiel erst durch eine Frage des Kunden auf.
|
||||
do $$
|
||||
declare
|
||||
v_def text;
|
||||
begin
|
||||
select pg_get_functiondef(p.oid) into v_def
|
||||
from pg_proc p join pg_namespace n on n.oid = p.pronamespace
|
||||
where n.nspname = 'public' and p.proname = 'terminate_employee' and p.prokind = 'f';
|
||||
|
||||
if v_def not like '%valid_from >= v_exit%' then
|
||||
raise exception 'terminate_employee raeumt die Besetzung vom selben Tag nicht ab.';
|
||||
end if;
|
||||
if v_def not like '%No Show%' then
|
||||
raise exception 'terminate_employee kennt den Nichtantritt nicht mehr.';
|
||||
end if;
|
||||
if v_def not like '%v_note%' then
|
||||
raise exception 'terminate_employee schreibt die Anmerkung nicht.';
|
||||
end if;
|
||||
if v_def not like '%austrittsart%' then
|
||||
raise exception 'terminate_employee schreibt die Austrittsart nicht.';
|
||||
end if;
|
||||
if v_def not like '%require_hr_admin()%' then
|
||||
raise exception 'terminate_employee prueft die Rechte nicht.';
|
||||
end if;
|
||||
if v_def not like '%search_path%' then
|
||||
raise exception 'terminate_employee hat keinen festen search_path.';
|
||||
end if;
|
||||
|
||||
raise notice 'terminate_employee: Austritt am selben Tag abgeraeumt.';
|
||||
end
|
||||
$$;
|
||||
Reference in New Issue
Block a user