91 lines
3.8 KiB
Go
91 lines
3.8 KiB
Go
package store
|
|
|
|
import "testing"
|
|
|
|
// TestCheckpointUsageForBookIsScopedToTheBook pins the book filter of CheckpointUsageForBook — the only
|
|
// thing between one book's consent number and another book's money when two books share a project
|
|
// database (pipeline/reprice.go keys calls by POSITION, and positions coincide across books). Removing
|
|
// `WHERE j.book_id = ?` left every store and money test green (backlog row 197 / ФЧ-1, reproduced by the
|
|
// acceptance), because no fixture had two books in one file. This one does, at the same position.
|
|
func TestCheckpointUsageForBookIsScopedToTheBook(t *testing.T) {
|
|
s, _ := openTemp(t)
|
|
jobA := mustSnapshotAndJob(t, s) // book "book", chapter 1, draft
|
|
jobB, err := s.EnsureJob("other-book", 1, "draft", "snap1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, cp := range []struct {
|
|
book string
|
|
job int64
|
|
hash string
|
|
cost float64
|
|
}{
|
|
{"book", jobA.ID, "a0", 0.01},
|
|
{"other-book", jobB.ID, "b0", 0.05}, // the same position, written later, five times the money
|
|
} {
|
|
res, _, err := s.Reserve(cp.book, cp.cost, Ceilings{BookUSD: 100, DayUSD: 100})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := s.SettleWithCheckpoint(res, cp.cost, Checkpoint{
|
|
RequestHash: cp.hash, JobID: cp.job, ChunkIdx: 0, Attempt: 0, Stage: "draft",
|
|
Role: "translator", ModelRequested: "m", ModelActual: "m", UsageJSON: "{}", CostUSD: cp.cost,
|
|
}, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
for _, want := range []struct {
|
|
book string
|
|
cost float64
|
|
}{{"book", 0.01}, {"other-book", 0.05}} {
|
|
rows, err := s.CheckpointUsageForBook(want.book)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(rows) != 1 || rows[0].CostUSD != want.cost {
|
|
t.Fatalf("%s: got %d row(s) %+v, want exactly its own call at $%.2f — another book's checkpoint at the same position reached the consent number's input", want.book, len(rows), rows, want.cost)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestCheckpointUsageCarriesTheEscalationFlag pins the OTHER column the re-pricing reads through this
|
|
// query. A hop call's tokens went to the stage's escalate_to model, so «the model this stage resolves to
|
|
// now» is the current hop for that row and the primary's slug for every other one (pipeline/reprice.go);
|
|
// with the flag lost, a hop call is compared against the primary and priced at the wrong table.
|
|
//
|
|
// ⚠ IT IS PINNED HERE AS WELL AS IN THE PIPELINE, by the same argument the book filter is: dropping
|
|
// `c.escalation` from the SELECT survives this package's battery while only the pipeline's goes red, and a
|
|
// property whose only guard lives in another package is one a refactor of THIS package can remove without
|
|
// anything here noticing. The store's contract is «return what the checkpoint holds»; that is a store
|
|
// statement and it is held here.
|
|
func TestCheckpointUsageCarriesTheEscalationFlag(t *testing.T) {
|
|
s, _ := openTemp(t)
|
|
job := mustSnapshotAndJob(t, s)
|
|
for _, cp := range []struct {
|
|
hash string
|
|
esc bool
|
|
}{{"primary", false}, {"hop", true}} {
|
|
res, _, err := s.Reserve("book", 0.01, Ceilings{BookUSD: 100, DayUSD: 100})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := s.SettleWithCheckpoint(res, 0.01, Checkpoint{
|
|
RequestHash: cp.hash, JobID: job.ID, ChunkIdx: 0, Stage: "draft", Role: "translator",
|
|
ModelRequested: "m", ModelActual: "m", UsageJSON: "{}", CostUSD: 0.01, Escalation: cp.esc,
|
|
}, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
rows, err := s.CheckpointUsageForBook("book")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(rows) != 2 {
|
|
t.Fatalf("got %d row(s), want the primary and its hop", len(rows))
|
|
}
|
|
// Insertion order is this query's contract (see the test above), so the hop is the second row.
|
|
if rows[0].Escalation || !rows[1].Escalation {
|
|
t.Fatalf("the escalation flag must travel with the call it belongs to; got primary=%v hop=%v",
|
|
rows[0].Escalation, rows[1].Escalation)
|
|
}
|
|
}
|