74 lines
3 KiB
Go
74 lines
3 KiB
Go
package books
|
|
|
|
import (
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"textmachine/platform/internal/ingest"
|
|
"textmachine/platform/internal/runner"
|
|
)
|
|
|
|
// The one claim about this render that no unit test can make: that what it produces is a
|
|
// configuration THE ENGINE LOADS.
|
|
//
|
|
// Everything else here is checked against this zone's own idea of the engine's schema, and that idea
|
|
// is exactly what goes stale — a required key added upstream, a stricter decoder, a field whose type
|
|
// changed. So the assertion is made by running the real binary: `tmctl manifest` is $0, needs no
|
|
// provider key, and fails loudly on a configuration it cannot load, which is precisely the question.
|
|
//
|
|
// It is GATED and named out loud, in the shape this zone already uses for its database tests: a
|
|
// battery on a bare clone has no engine binary and must stay green. Run it with
|
|
//
|
|
// TM_PLATFORM_TEST_ENGINE_BIN=<path to tmctl> \
|
|
// TM_PLATFORM_TEST_BOOK_TEMPLATE=<path to a deployment template> go test ./internal/books/
|
|
func TestTheRenderedConfigurationIsOneTheEngineActuallyLoads(t *testing.T) {
|
|
bin := os.Getenv("TM_PLATFORM_TEST_ENGINE_BIN")
|
|
tpl := os.Getenv("TM_PLATFORM_TEST_BOOK_TEMPLATE")
|
|
if bin == "" || tpl == "" {
|
|
t.Skip("TM_PLATFORM_TEST_ENGINE_BIN and TM_PLATFORM_TEST_BOOK_TEMPLATE not set: " +
|
|
"the rendered configuration is not checked against a real engine")
|
|
}
|
|
dir := t.TempDir()
|
|
// The source the intake would have written, under the name the intake gives it. Three chapters so
|
|
// the manifest has something to count.
|
|
var body strings.Builder
|
|
for i := 1; i <= 3; i++ {
|
|
body.WriteString("第" + string(rune('0'+i)) + "章 测试\n")
|
|
body.WriteString(strings.Repeat("这是一个测试文本。", 40))
|
|
body.WriteString("\n\n")
|
|
}
|
|
if err := os.WriteFile(filepath.Join(dir, SourceName+".txt"), []byte(body.String()), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
svc := &Service{Cfg: Config{BooksDir: filepath.Dir(dir), BookTemplate: tpl}}
|
|
if err := svc.provision(t.Context(), dir, bookConfig{
|
|
ID: "bk_LIVEPROBE", Title: "蛊真人", SourceLang: "zh", TargetLang: "ru",
|
|
}); err != nil {
|
|
t.Fatalf("provision: %v", err)
|
|
}
|
|
cmd := exec.CommandContext(t.Context(), bin, runner.ManifestArgs(dir)...)
|
|
cmd.Dir = dir
|
|
var errOut strings.Builder
|
|
cmd.Stderr = &errOut
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
rendered, _ := os.ReadFile(filepath.Join(dir, runner.ConfigFile))
|
|
t.Fatalf("the engine refused the rendered configuration: %v\n--- stderr ---\n%s\n--- book.yaml ---\n%s",
|
|
err, errOut.String(), rendered)
|
|
}
|
|
m, err := ingest.DecodeManifest(out)
|
|
if err != nil {
|
|
t.Fatalf("the manifest did not decode: %v", err)
|
|
}
|
|
if m.ChaptersTotal != 3 {
|
|
t.Errorf("the engine cut %d chapters out of three", m.ChaptersTotal)
|
|
}
|
|
// The identity the platform wrote is the identity the engine read back: one book id on both sides
|
|
// of the seam, which is what lets the handshake's book_id be compared with the row at all.
|
|
if m.ChunkerVersion == "" || m.SourceSHA256 == "" {
|
|
t.Errorf("the manifest carries no provenance: %+v", m)
|
|
}
|
|
}
|