textmachine/platform/internal/runs/operatorverdict_test.go

94 lines
4.4 KiB
Go

package runs
import (
"testing"
"textmachine/platform/internal/pgstore"
)
// ⛔ AN OPERATOR'S TERMINAL VERDICT IS RECORDED AS ONE, and until this pack nothing recorded it.
//
// `run abandon` writes the run `failed` with `service_error`. On the WIRE that is right and stays:
// the client's question there is «is a retry worth offering», and it is not — whatever wedged the run
// is still whatever it was. But nothing anywhere said that a PERSON had decided, so the run wore a
// fault it never had, which is the class of unified backlog row 394 one level up: our own policy read
// as a broken deployment. The column that exists for «what this platform concluded» now carries it.
//
// ⚠ The wire word is asserted TOO, and deliberately: a fix that had moved it would have traded one
// wrong answer for another, since `abandoned` says nothing about whether a retry helps.
func TestAnOperatorsVerdictIsRecordedAsHisAndNotAsAFault(t *testing.T) {
f := newFixture(t, "10", 500)
run, err := f.svc.Start(f.ctx, StartRequest{UserID: "u1", BookID: f.bookID(t), Chapters: order(10)})
if err != nil {
t.Fatal(err)
}
if err := f.svc.Spawn(f.ctx, run.ID); err != nil {
t.Fatal(err)
}
// The floor the command waits for: seeing a run go wrong and being allowed to end it are
// different permissions, so the row has to be stalled before a verdict is accepted at all.
if _, err := f.store.Pool().Exec(f.ctx,
`update run_attempts set reconcile_failures = $2 where run_id = $1`, run.ID, StalledAfter); err != nil {
t.Fatal(err)
}
if _, err := f.store.AbandonRun(f.ctx, proven(t, f, run.ID, "systemd says the unit is gone")); err != nil {
t.Fatalf("a proven stalled run could not be given up on: %v", err)
}
var result, reason, status string
if err := f.store.Pool().QueryRow(f.ctx, `
select coalesce(a.exit_result, ''), coalesce(r.failure_reason, ''), r.status
from runs r join run_attempts a on a.run_id = r.id
where r.id = $1 order by a.attempt_no desc limit 1`, run.ID).
Scan(&result, &reason, &status); err != nil {
t.Fatal(err)
}
// ⛔ THE LITERAL, NOT THE CONSTANT, and that is the PD-1 class this zone names: a test that reads
// the same constant the code writes passes at ANY value, the empty string included. Proved rather
// than argued — this pack's mutation campaign emptied the constant and the first edition of this
// assertion stayed green.
if result != "abandoned" {
t.Errorf("the abandoned attempt's exit_result is %q, want %q: whose decision ended this run is "+
"not recorded anywhere", result, "abandoned")
}
// The constant and the literal are asserted to be the same thing ONCE, here, so the value the code
// writes cannot drift from the value this test demands without one of the two lines going red.
if pgstore.AbandonedResult != "abandoned" {
t.Errorf("pgstore.AbandonedResult is %q: the word an operator's verdict is recorded under has "+
"moved, and every reader of the column now reads a different history", pgstore.AbandonedResult)
}
if status != "failed" || reason != "service_error" {
t.Errorf("the abandoned run reads %s/%s, want failed/service_error — the client's retry answer "+
"must not move with this", status, reason)
}
}
// ⚠ AND A MACHINE VERDICT ALREADY ON THE ROW IS NEVER OVERWRITTEN: an attempt whose unit had ended
// carries what the machine said, and an operator's word about the RUN must not erase it. The
// settlement branch of the same command is the one that reaches such a row.
func TestAnOperatorsWordDoesNotOverwriteWhatTheMachineSaid(t *testing.T) {
f := newFixture(t, "10", 500)
run, err := f.svc.Start(f.ctx, StartRequest{UserID: "u1", BookID: f.bookID(t), Chapters: order(10)})
if err != nil {
t.Fatal(err)
}
if err := f.svc.Spawn(f.ctx, run.ID); err != nil {
t.Fatal(err)
}
// The machine's own word, as the ordinary ending writes it.
if _, err := f.store.Pool().Exec(f.ctx,
`update run_attempts set exit_result = 'oom-kill', reconcile_failures = $2 where run_id = $1`,
run.ID, StalledAfter); err != nil {
t.Fatal(err)
}
if _, err := f.store.AbandonRun(f.ctx, proven(t, f, run.ID, "the host took it for its memory")); err != nil {
t.Fatalf("abandon: %v", err)
}
var result string
if err := f.store.Pool().QueryRow(f.ctx,
`select coalesce(exit_result, '') from run_attempts where run_id = $1`, run.ID).Scan(&result); err != nil {
t.Fatal(err)
}
if result != "oom-kill" {
t.Errorf("exit_result is %q: an operator's verdict overwrote what the machine said about the unit", result)
}
}