textmachine/backend/internal/pipeline/snapshot_wave_test.go

71 lines
2.9 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 pipeline
import (
"strings"
"testing"
"textmachine/backend/internal/store"
)
// snapshot_wave_test.go: WS1 §1в per-wave snapshot mechanics (R1 ADDITIVE sub-step — the wave executor
// itself is residual; this pins the snapshot machinery it will use, WITHOUT switching the driver). The
// book-global snapshotID() is byte-unchanged (TestGolden proves it); these tests exercise the new
// snapshotIDForWave.
func TestSnapshotIDForWave(t *testing.T) {
r := newRunner(t, setupProject(t, "http://127.0.0.1:1"))
defer r.Close()
seed := []store.GlossaryEntry{
{Src: "方源", Dst: "Фан Юань", Status: "approved", Source: "seed"},
{Src: "古月", Dst: "Гу Юэ", Status: "approved", Source: "ruby"},
}
r.memory = materializeMemory(seed, false)
w1id, w1p, err := r.snapshotIDForWave(waveDraft)
if err != nil {
t.Fatal(err)
}
w2id, w2p, err := r.snapshotIDForWave(waveEdit)
if err != nil {
t.Fatal(err)
}
// the draft wave and the edit wave differ (different stage subset AND different bank version).
if w1id == w2id {
t.Fatalf("draft-wave snapshot must differ from snapshot_W2 (stage subset + bank version)")
}
// The stage PARTITION: the draft wave folds the draft (translator) stage, the edit wave folds the edit (editor) stage.
if !strings.Contains(w1p, `"name":"draft"`) || strings.Contains(w1p, `"name":"edit"`) {
t.Fatalf("draft-wave snapshot must fold ONLY the draft stage, payload: %s", w1p)
}
if !strings.Contains(w2p, `"name":"edit"`) || strings.Contains(w2p, `"name":"draft"`) {
t.Fatalf("snapshot_W2 must fold ONLY the edit stage, payload: %s", w2p)
}
// «Переоплата ОДНА» at the snapshot level (§1в): a the draft wave.5 mined-approved addition moves ONLY the edit wave.
enriched := append(append([]store.GlossaryEntry{}, seed...), store.GlossaryEntry{
Src: "蛊", Dst: "гу", Status: "approved", Source: "mined",
})
r.memory = materializeMemory(enriched, false)
w1id2, _, _ := r.snapshotIDForWave(waveDraft)
w2id2, _, _ := r.snapshotIDForWave(waveEdit)
if w1id2 != w1id {
t.Fatalf("draft-wave snapshot moved on a mined-approved addition — the draft wave checkpoints would re-bill («переоплата ОДНА» broken)")
}
if w2id2 == w2id {
t.Fatalf("snapshot_W2 did NOT move on a mined-approved addition — the edit wave would miss the mined canon")
}
}
// TestWaveStagesPartition pins the role partition independently of the runner.
func TestWaveStagesPartition(t *testing.T) {
r := newRunner(t, setupProject(t, "http://127.0.0.1:1"))
defer r.Close()
draftStages := waveStages(r.Pipeline.Stages, waveDraft)
editStages := waveStages(r.Pipeline.Stages, waveEdit)
if len(draftStages) != 1 || draftStages[0].Role != roleTranslator {
t.Fatalf("the draft wave must be the translator stage(s), got %+v", draftStages)
}
if len(editStages) != 1 || editStages[0].Role != roleEditor {
t.Fatalf("the edit wave must be the editor stage(s), got %+v", editStages)
}
}