Files
narratio/internal/config/scriptorium_test.go
Eric Rakestraw 33f7ae8f2e
All checks were successful
ci/woodpecker/tag/release Pipeline was successful
Simplify downstream tool configuration
2026-05-16 23:30:40 +00:00

236 lines
6.0 KiB
Go

package config
import (
"strings"
"testing"
)
func TestScriptoriumLoadAndValidate(t *testing.T) {
tests := []struct {
name string
scriptoriumYAML string
wantLoadErr string
wantValidateErr string
assert func(t *testing.T, cfg *Config)
}{
{
name: "valid minimal scriptorium config",
scriptoriumYAML: `scriptorium:
binary: scriptorium
artifacts:
session_recap:
enabled: true
prompt_id: dnd.session_recap
output_path: artifacts/session_recap.md
inputs:
transcript:
source: processed_transcript
required: true
vars:
session_id: true
output_kind: session_recap
`,
assert: func(t *testing.T, cfg *Config) {
t.Helper()
if cfg.Pipeline.Scriptorium == nil {
t.Fatal("scriptorium config should be present")
}
if cfg.Pipeline.Scriptorium.Timeout != "10m" {
t.Fatalf("scriptorium.timeout default = %q, want 10m", cfg.Pipeline.Scriptorium.Timeout)
}
},
},
{
name: "unknown scriptorium field fails",
scriptoriumYAML: `scriptorium:
binary: scriptorium
bogus: true
`,
wantLoadErr: "strict decode failed",
},
{
name: "missing binary defaults when section present",
scriptoriumYAML: `scriptorium:
timeout: 10m
`,
assert: func(t *testing.T, cfg *Config) {
t.Helper()
if cfg.Pipeline.Scriptorium == nil {
t.Fatal("scriptorium config should be present")
}
if cfg.Pipeline.Scriptorium.Binary != "scriptorium" {
t.Fatalf("scriptorium.binary = %q, want scriptorium", cfg.Pipeline.Scriptorium.Binary)
}
},
},
{
name: "enabled artifact missing prompt id fails",
scriptoriumYAML: `scriptorium:
binary: scriptorium
artifacts:
session_recap:
enabled: true
output_path: artifacts/session_recap.md
`,
wantValidateErr: "pipeline.scriptorium.artifacts.session_recap.prompt_id is required when enabled",
},
{
name: "enabled artifact missing output path fails",
scriptoriumYAML: `scriptorium:
binary: scriptorium
artifacts:
session_recap:
enabled: true
prompt_id: dnd.session_recap
`,
wantValidateErr: "pipeline.scriptorium.artifacts.session_recap.output_path is required when enabled",
},
{
name: "invalid timeout fails",
scriptoriumYAML: `scriptorium:
binary: scriptorium
timeout: definitely-not-a-duration
`,
wantValidateErr: "pipeline.scriptorium.timeout must be a valid duration",
},
{
name: "optional previous recap input is accepted",
scriptoriumYAML: `scriptorium:
binary: scriptorium
artifacts:
session_recap:
enabled: true
prompt_id: dnd.session_recap
output_path: artifacts/session_recap.md
inputs:
transcript:
source: processed_transcript
required: true
previous_recap:
source: previous_session_artifact
artifact: session_recap
path: ""
required: false
vars:
session_id: true
output_kind: session_recap
`,
},
{
name: "artifact render_debug override is accepted",
scriptoriumYAML: `scriptorium:
binary: scriptorium
render_debug: false
artifacts:
session_recap:
enabled: true
render_debug: true
prompt_id: dnd.session_recap
output_path: artifacts/session_recap.md
inputs:
transcript:
source: processed_transcript
required: true
`,
assert: func(t *testing.T, cfg *Config) {
t.Helper()
artifact := cfg.Pipeline.Scriptorium.Artifacts["session_recap"]
if artifact.RenderDebug == nil || *artifact.RenderDebug != true {
t.Fatalf("artifact render_debug = %#v, want true", artifact.RenderDebug)
}
},
},
{
name: "multiple artifact definitions can be decoded",
scriptoriumYAML: `scriptorium:
binary: scriptorium
artifacts:
session_recap:
enabled: true
prompt_id: dnd.session_recap
output_path: artifacts/session_recap.md
inputs:
transcript:
source: processed_transcript
required: true
player_summary:
enabled: true
prompt_id: dnd.player_summary
profile_id: local-fast
output_path: artifacts/player_summary.md
timeout: 3m
inputs:
transcript:
source: processed_transcript
required: true
`,
assert: func(t *testing.T, cfg *Config) {
t.Helper()
if cfg.Pipeline.Scriptorium == nil {
t.Fatal("scriptorium config should be present")
}
if len(cfg.Pipeline.Scriptorium.Artifacts) != 2 {
t.Fatalf("scriptorium.artifacts count = %d, want 2", len(cfg.Pipeline.Scriptorium.Artifacts))
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pipelineYAML := testPipelineBaseYAML + "\n" + tt.scriptoriumYAML
pipelinePath, sessionPath := writeConfigFiles(t, pipelineYAML, testSessionBaseYAML)
cfg, err := Load(pipelinePath, sessionPath)
if tt.wantLoadErr != "" {
if err == nil {
t.Fatalf("expected load error containing %q, got nil", tt.wantLoadErr)
}
if !strings.Contains(err.Error(), tt.wantLoadErr) {
t.Fatalf("load error = %q, want to contain %q", err.Error(), tt.wantLoadErr)
}
return
}
if err != nil {
t.Fatalf("Load() error = %v", err)
}
if tt.assert != nil {
tt.assert(t, cfg)
}
err = Validate(cfg)
if tt.wantValidateErr != "" {
if err == nil {
t.Fatalf("expected validation error containing %q, got nil", tt.wantValidateErr)
}
if !strings.Contains(err.Error(), tt.wantValidateErr) {
t.Fatalf("validation error = %q, want to contain %q", err.Error(), tt.wantValidateErr)
}
return
}
if err != nil {
t.Fatalf("Validate() error = %v", err)
}
})
}
}
const testPipelineBaseYAML = `workspace:
root: /tmp/narratio
whisperx:
transcribe_url: https://transcription.ai.rakestrawhome.com/transcribe
seriatim:
binary: seriatim
audita:
binary: audita
`
const testSessionBaseYAML = `session_id: 2026-05-03
inputs:
audio_dir: ./audio
speakers_file: ./speakers.yml
autocorrect_file: ./autocorrect.yml
glossary_file: ./glossary.yml
`