textmachine/platform/internal/runs/lagging_test.go

172 lines
7.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package runs
import (
"testing"
"time"
"textmachine/platform/internal/ingest"
"textmachine/platform/internal/money"
"textmachine/platform/internal/runner"
)
// ⛔ THE BUYER IS TOLD THAT THE FIGURES ARE BEHIND, THROUGH THE SURFACE THAT CARRIES THE FIGURES.
//
// A parked or quarantined projection leaves a paying run's bar standing while the run goes on
// spending, and until this field the operator had four carriers for it and the buyer none (unified
// backlog row 399). ⚠ The screen does not merely freeze: the repair channel keeps refreshing the
// ESTIMATE of such an attempt while the bar cannot move, so a client reading both shows a moving
// estimate over a standing bar.
//
// ⚠ BOTH STATES ARE HERE BECAUSE THE FIELD ANSWERS FOR BOTH, and a field named «the figures are
// behind» that went quiet on the quarantine would lie over half of its own population. The control
// row is what keeps the pin from passing over a field hard-wired to true.
func TestARunWhoseProjectionIsNotFollowingItSaysSoToTheBuyer(t *testing.T) {
for _, tc := range []struct {
name string
set string
want bool
}{
{"the journal continued under another stream id", `parked_at = now()`, true},
{"the stream cannot be materialised at all", `quarantine_reason = 'a gap in the stream'`, true},
{"the projection is keeping up", `parked_at = null`, false},
} {
t.Run(tc.name, func(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)
}
live := f.live(t)
if _, err := f.store.Pool().Exec(f.ctx,
`update run_attempts set `+tc.set+` where id = $1`, live.AttemptID); err != nil {
t.Fatal(err)
}
// The read path a client is served from, not the column: what the buyer is told is the
// question, and three different reads share one shape (pgstore.runRow).
got, err := f.store.ReadRun(f.ctx, "u1", run.ID)
if err != nil {
t.Fatal(err)
}
if got.ProgressLagging != tc.want {
t.Errorf("progress_lagging is %v, want %v", got.ProgressLagging, tc.want)
}
// ⚠ The premise of the whole field: the run is LIVE while this is said. A field that only
// ever came out true on a finished run would describe nothing a buyer is watching.
if got.Status != "translating" {
t.Errorf("the run is %q, so this fixture no longer measures a live run's screen", got.Status)
}
})
}
}
// ⚠ AND THE FACT IS THE LIVE ATTEMPT'S, not the run's history: a park that ENDED with an earlier
// attempt says nothing about the figures a buyer is watching now, and reporting it would tell them
// their screen is behind while it is perfectly current.
func TestAParkAnEarlierAttemptEndedWithIsNotReportedAsTodaysLag(t *testing.T) {
f := newFixture(t, "10", 500)
run, err := f.svc.Start(f.ctx, StartRequest{UserID: "u1", BookID: f.bookID(t), Chapters: order(100)})
if err != nil {
t.Fatal(err)
}
if err := f.svc.Spawn(f.ctx, run.ID); err != nil {
t.Fatal(err)
}
first := f.live(t)
// The attempt is replaced the ordinary way: its unit is gone, nothing was spent, and the run comes
// back with a second attempt whose projection has never parked.
f.engine.set(ingest.StatusReport{TotalUnits: 100, Done: 0, Spend: usd(0), Reserved: usd(0)}, nil)
f.runner.alive = false
f.svc.Now = func() time.Time { return f.now.Add(time.Hour) }
if err := f.svc.Sweep(f.ctx); err != nil {
t.Fatal(err)
}
if live := f.live(t); live.AttemptNo != 2 {
t.Fatalf("attempt %d: this test needs the parked attempt to be the PREVIOUS one", live.AttemptNo)
}
// ⛔ THE PARK IS SET AFTER THE SWEEP, AND THAT ORDER IS THE FIXTURE'S WHOLE VALIDITY. Set before
// it, the mark does not survive: the same pass drains a journal this fixture never wrote, reaches
// the verdict «not parked» and clears the column (reconcile.drainJournal → MarkParked). So a park
// planted earlier is simply gone by the time anything reads it, and the test would measure an
// empty scenario. Found by this pack's own mutation campaign: the planting that removes the
// live-attempt condition from the read survived the first edition of this test, green.
if _, err := f.store.Pool().Exec(f.ctx,
`update run_attempts set parked_at = now() where id = $1`, first.AttemptID); err != nil {
t.Fatal(err)
}
// The premise, asserted rather than assumed: the ENDED attempt really does carry a park now.
var ended bool
var parked *time.Time
if err := f.store.Pool().QueryRow(f.ctx,
`select ended_at is not null, parked_at from run_attempts where id = $1`, first.AttemptID).
Scan(&ended, &parked); err != nil {
t.Fatal(err)
}
if !ended || parked == nil {
t.Fatalf("the previous attempt reads ended=%v parked=%v: without both this test cannot tell a "+
"history from today's lag", ended, parked)
}
got, err := f.store.ReadRun(f.ctx, "u1", run.ID)
if err != nil {
t.Fatal(err)
}
if got.ProgressLagging {
t.Error("a park the previous attempt ended with is reported as today's lag")
}
}
// ⛔ WHAT A RESUME IS PERMISSION FOR IS VISIBLE WITH THE RUN IT APPLIES TO.
//
// The consent is granted by the user's own resume of a corrected book and was, until this field,
// recorded nowhere a person could read: measured once at 78× the work actually re-bought (unified
// backlog row 416). This does not CAP it — the figure to cap against does not exist on this side of
// the seam — it makes the figure and its provenance sayable: it is the run's own hold.
//
// The control is the same fixture without a correction: no consent stands, and the field says so
// rather than showing a zero that reads as «consent to nothing».
func TestTheConsentAResumeGrantedIsVisibleWithItsRun(t *testing.T) {
for _, tc := range []struct {
name string
corrected bool
}{
{"a resume over a corrected bank", true},
{"a resume of an ordinary stopped run", false},
} {
t.Run(tc.name, func(t *testing.T) {
f := newFixture(t, "10", 500)
runID := f.stoppedRun(t, StartRequest{UserID: "u1", BookID: f.bookID(t), Chapters: order(3)}, 0,
runner.Marker{Result: "exit-code", Code: "exited", Status: "3", At: f.now.Add(time.Second)})
if tc.corrected {
fake := &fakeBankApplier{
out: runner.BankApplyOutcome{ExitCode: 0, Exited: true, Report: okReport("apply"), Decoded: true},
}
fake.out.Report.BookID = f.bookID(t)
f.svc.Bank = fake
if _, err := f.svc.ApplyBankCorrections(f.ctx, BankCorrectionsInput{
UserID: "u1", BookID: f.bookID(t), Preview: false,
Decisions: []ingest.BankDecision{{Action: "decline", ID: "tm_1"}},
}); err != nil {
t.Fatal(err)
}
}
if _, err := f.svc.Resume(f.ctx, "u1", runID); err != nil {
t.Fatal(err)
}
got, err := f.store.ReadRun(f.ctx, "u1", runID)
if err != nil {
t.Fatal(err)
}
want := money.MicroUSD(0)
if tc.corrected {
// The provenance, asserted as such: the run's OWN hold — what three chapters were
// sold for — and not a projection of the re-purchase, which does not exist here.
want = fixtureHold(3)
}
if got.RebillConsent != want {
t.Errorf("the run is handed out with a consent of %s, want %s", got.RebillConsent.USD(), want.USD())
}
})
}
}