98 lines
4.1 KiB
Go
98 lines
4.1 KiB
Go
package runner
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// The repair channel against the REAL shell contract. `status --json` is what settles a run's money
|
|
// and what the pre-spawn meter reads, and the engine exits 2 from it for any book that has ever
|
|
// flagged a unit — with the report already printed. These run a real process for the same reason the
|
|
// manifest tests do: what is being pinned is a disposition of os/exec, not a value we choose.
|
|
|
|
// Bare decimals, as the engine writes them (pipeline.StatusReport binds both figures to float64).
|
|
const flaggedReport = `{"book_id":"gu","total_units":10,"done":9,"flagged":1,
|
|
"committed_usd":1.25,"reserved_usd":0.1}`
|
|
|
|
func TestAFlaggedBookStillAnswersAboutItsMoney(t *testing.T) {
|
|
// Exactly what the engine does: the whole document on stdout, the sentinel's message on stderr,
|
|
// exit 2 (backend/cmd/tmctl/render.go renderStatusJSON).
|
|
bin := fakeEngine(t, `cat <<'JSON'
|
|
`+flaggedReport+`
|
|
JSON
|
|
echo "tmctl: 1 of 10 unit(s) flagged" >&2
|
|
exit 2`)
|
|
rep, err := New(nil).Status(t.Context(), bin, t.TempDir())
|
|
if err != nil {
|
|
t.Fatalf("a flagged book could not be read: %v", err)
|
|
}
|
|
if rep.Spend == nil || rep.Reserved == nil {
|
|
t.Fatalf("the money of a flagged book did not survive the exit code: %+v", rep)
|
|
}
|
|
if *rep.Spend != 1_250_000 || rep.Flagged != 1 {
|
|
t.Errorf("report %+v, want committed 1.25 and one flagged unit", rep)
|
|
}
|
|
}
|
|
|
|
func TestExitTwoWithNothingToReadIsStillARefusal(t *testing.T) {
|
|
bin := fakeEngine(t, `echo "=== STATUS: gu ==="; exit 2`)
|
|
if _, err := New(nil).Status(t.Context(), bin, t.TempDir()); err == nil {
|
|
t.Fatal("a human dashboard was accepted as a report because the code was 2")
|
|
} else if !strings.Contains(err.Error(), "tmctl status") {
|
|
t.Errorf("the error does not name what failed: %v", err)
|
|
}
|
|
}
|
|
|
|
// The boundary in the other direction: only 2 is a completed command. A refusal that happens to
|
|
// print a document is still a refusal — the report it printed describes a book the engine did not
|
|
// finish reading.
|
|
func TestAReportPrintedByAFailedCallIsNotAnAnswer(t *testing.T) {
|
|
for _, code := range []string{"1", "11", "13"} {
|
|
bin := fakeEngine(t, `cat <<'JSON'
|
|
`+flaggedReport+`
|
|
JSON
|
|
exit `+code)
|
|
if _, err := New(nil).Status(t.Context(), bin, t.TempDir()); err == nil {
|
|
t.Errorf("exit %s with a document on stdout was read as an answer", code)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Exit 2 is taken only when the report AGREES that the book has a flagged unit — the one condition
|
|
// under which the engine emits that code from `status --json`. Without it, anything at the pinned
|
|
// path that prints a JSON object with a committed figure and exits 2 is CHARGED rather than
|
|
// deferred: a wrapper, a version directory replaced in place, a half-finished deploy. Measured by
|
|
// the money lens of the dofix review, which settled 2.5 USD against three such answers.
|
|
//
|
|
// Mutation caught: taking exit 2 on the code and a parse alone.
|
|
func TestExitTwoIsTakenOnlyFromAReportThatAgreesWithIt(t *testing.T) {
|
|
for name, body := range map[string]string{
|
|
"a report with nothing flagged": `{"book_id":"gu","total_units":10,"done":10,"flagged":0,"committed_usd":2.5,"reserved_usd":0}`,
|
|
"a document that is not one": `{"committed_usd":2.5}`,
|
|
"an empty object": `{}`,
|
|
"the JSON literal null": `null`,
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
bin := fakeEngine(t, `cat <<'JSON'
|
|
`+body+`
|
|
JSON
|
|
exit 2`)
|
|
if _, err := New(nil).Status(t.Context(), bin, t.TempDir()); err == nil {
|
|
t.Error("exit 2 was taken from a report that does not carry a flagged unit")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// The cap is on the same threat as the manifest's — a process at the configured path that is not the
|
|
// engine — and it must not be reachable by a real book: a 2283-chapter report measures 1.1 MB.
|
|
func TestAnEndlessStatusIsRefusedRatherThanRead(t *testing.T) {
|
|
bin := fakeEngine(t, `exec yes '{"book_id":"gu"}'`)
|
|
_, err := New(nil).Status(t.Context(), bin, t.TempDir())
|
|
if err == nil {
|
|
t.Fatal("an endless report was read to the end")
|
|
}
|
|
if !strings.Contains(err.Error(), "more than this platform will read") {
|
|
t.Errorf("the refusal does not name the cap: %v", err)
|
|
}
|
|
}
|