94 lines
4 KiB
Go
94 lines
4 KiB
Go
package store
|
|
|
|
import "testing"
|
|
|
|
// waveselection_test.go: the per-wave record (schema v17). These are store-level because the property being
|
|
// pinned is the UPSERT's, and a pipeline fixture cannot reach it: a re-run of the same book re-derives an
|
|
// IDENTICAL selection, so every column could be dropped from the update clause and the round trip would
|
|
// still agree with itself. The acceptance found exactly that hole.
|
|
|
|
func waveRow(wave string, hits int, srcs string) WaveSelection {
|
|
return WaveSelection{BookID: "book", Chapter: 1, ChunkIdx: 0, Wave: wave, SnapshotID: "snap",
|
|
NExactHits: hits, InjectedSrcs: srcs}
|
|
}
|
|
|
|
// TestEveryColumnOfAWaveRecordIsRewrittenOnConflict pins that a re-derived selection REPLACES the stored
|
|
// one, column by column. The record is recomputed on every run, so a column left out of the update clause
|
|
// keeps the first run's value forever — and `injected_srcs` in particular is the attribution this table was
|
|
// built for: which rows the editor was actually shown. A stale list answers the question wrongly and looks
|
|
// exactly like a fresh one.
|
|
func TestEveryColumnOfAWaveRecordIsRewrittenOnConflict(t *testing.T) {
|
|
s, _ := openTemp(t)
|
|
first := waveRow(WaveEdit, 3, `["方源"]`)
|
|
first.NSticky, first.NAmbiguousFlagged, first.NSpoilerBlocked, first.NEvicted = 1, 2, 3, 4
|
|
first.EvictedSrcs = `["古月"]`
|
|
if err := s.UpsertWaveSelection(first); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// A LATER run over the same position that saw something different — the case a same-book re-run can
|
|
// never produce, and therefore the case no pipeline fixture can pin.
|
|
second := waveRow(WaveEdit, 9, `["方源","蛊师"]`)
|
|
second.SnapshotID = "snap2"
|
|
second.NSticky, second.NAmbiguousFlagged, second.NSpoilerBlocked, second.NEvicted = 8, 7, 6, 5
|
|
second.EvictedSrcs = `["白家寨"]`
|
|
if err := s.UpsertWaveSelection(second); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := s.WaveSelectionsForBook("book")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(got) != 1 {
|
|
t.Fatalf("the same position and wave must hold ONE row, not accumulate: got %d", len(got))
|
|
}
|
|
g := got[0]
|
|
for _, c := range []struct {
|
|
col string
|
|
got, want any
|
|
}{
|
|
{"snapshot_id", g.SnapshotID, second.SnapshotID},
|
|
{"n_exact_hits", g.NExactHits, second.NExactHits},
|
|
{"n_sticky", g.NSticky, second.NSticky},
|
|
{"n_ambiguous_flagged", g.NAmbiguousFlagged, second.NAmbiguousFlagged},
|
|
{"n_spoiler_blocked", g.NSpoilerBlocked, second.NSpoilerBlocked},
|
|
{"n_evicted", g.NEvicted, second.NEvicted},
|
|
{"injected_srcs", g.InjectedSrcs, second.InjectedSrcs},
|
|
{"evicted_srcs", g.EvictedSrcs, second.EvictedSrcs},
|
|
} {
|
|
if c.got != c.want {
|
|
t.Errorf("%s was not rewritten by the later run: got %v, want %v — a column missing from the update clause keeps the first run's value forever", c.col, c.got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestTheTwoWavesAreSeparateRowsAtOnePosition pins the axis the table exists for. The draft and the editor
|
|
// select over different banks at the SAME chapter and chunk; if the wave were not in the key they would
|
|
// overwrite each other and the schema would be no better than the one-row-per-chunk table it was added
|
|
// beside.
|
|
func TestTheTwoWavesAreSeparateRowsAtOnePosition(t *testing.T) {
|
|
s, _ := openTemp(t)
|
|
if err := s.UpsertWaveSelection(waveRow(WaveDraft, 2, `["方源"]`)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := s.UpsertWaveSelection(waveRow(WaveEdit, 5, `["方源","蛊师"]`)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := s.WaveSelectionsForBook("book")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(got) != 2 {
|
|
t.Fatalf("one position, two waves, two rows: got %d — %+v", len(got), got)
|
|
}
|
|
by := map[string]WaveSelection{}
|
|
for _, w := range got {
|
|
by[w.Wave] = w
|
|
}
|
|
if by[WaveDraft].NExactHits != 2 || by[WaveEdit].NExactHits != 5 {
|
|
t.Errorf("the waves overwrote each other: draft=%d edit=%d, want 2 and 5", by[WaveDraft].NExactHits, by[WaveEdit].NExactHits)
|
|
}
|
|
if by[WaveDraft].InjectedSrcs == by[WaveEdit].InjectedSrcs {
|
|
t.Errorf("both waves report the same injected rows (%s) — the two select over different banks and the record must be able to say so", by[WaveDraft].InjectedSrcs)
|
|
}
|
|
}
|