558 lines
21 KiB
Go
558 lines
21 KiB
Go
package app
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.maximumdirect.net/eric/narratio/internal/config"
|
|
)
|
|
|
|
func TestConfigCommandHelpAndDispatch(t *testing.T) {
|
|
for _, test := range []struct {
|
|
name string
|
|
args []string
|
|
want string
|
|
code int
|
|
}{
|
|
{name: "top level help", args: []string{"config", "--help"}, want: "Usage: narratio config <validate|show|sources|diff>"},
|
|
{name: "validate help", args: []string{"config", "validate", "--help"}, want: "Usage: narratio config validate"},
|
|
{name: "show help", args: []string{"config", "show", "--help"}, want: "Usage: narratio config show"},
|
|
{name: "sources help", args: []string{"config", "sources", "--help"}, want: "Usage: narratio config sources"},
|
|
{name: "diff help", args: []string{"config", "diff", "--help"}, want: "Usage: narratio config diff"},
|
|
{name: "unknown", args: []string{"config", "unknown"}, want: `config: unknown subcommand "unknown"`, code: 1},
|
|
{name: "missing", args: []string{"config"}, want: "config: expected subcommand: validate|show|sources|diff", code: 1},
|
|
{name: "session flag", args: []string{"config", "validate", "--session", "session.yml"}, want: "flag provided but not defined", code: 1},
|
|
{name: "stage flag", args: []string{"config", "show", "--from", "prepare"}, want: "flag provided but not defined", code: 1},
|
|
{name: "force flag", args: []string{"config", "show", "--force"}, want: "flag provided but not defined", code: 1},
|
|
{name: "artifact flag", args: []string{"config", "show", "--artifacts", "recap"}, want: "flag provided but not defined", code: 1},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
var stdout, stderr bytes.Buffer
|
|
code := Execute(test.args, &stdout, &stderr)
|
|
if code != test.code {
|
|
t.Fatalf("exit code = %d, want %d; stdout=%q stderr=%q", code, test.code, stdout.String(), stderr.String())
|
|
}
|
|
combined := stdout.String() + stderr.String()
|
|
if !strings.Contains(combined, test.want) {
|
|
t.Fatalf("output = %q, want %q", combined, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConfigValidateAndShowPipelineOnlyAreSideEffectFree(t *testing.T) {
|
|
dir := t.TempDir()
|
|
workspaceRoot := filepath.Join(dir, "workspace-does-not-exist")
|
|
pipelinePath := filepath.Join(dir, "pipeline.yml")
|
|
secretsDir := filepath.Join(dir, "secrets")
|
|
const secret = "inspection-secret-must-not-escape"
|
|
mustWriteTestFile(t, filepath.Join(secretsDir, "INSPECTION_SECRET"), secret+"\n")
|
|
calls := 0
|
|
server := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) { calls++ }))
|
|
defer server.Close()
|
|
mustWriteTestFile(t, pipelinePath, `workspace:
|
|
root: `+workspaceRoot+`
|
|
secrets:
|
|
env_dir: `+secretsDir+`
|
|
whisperx:
|
|
transcribe_url: `+server.URL+`
|
|
`)
|
|
t.Setenv("INSPECTION_SECRET", secret)
|
|
|
|
var validateOut bytes.Buffer
|
|
if err := ConfigValidate(context.Background(), []string{"--config", pipelinePath}, &validateOut); err != nil {
|
|
t.Fatalf("ConfigValidate() error = %v", err)
|
|
}
|
|
if !strings.Contains(validateOut.String(), "Configuration valid: root=") || !strings.Contains(validateOut.String(), "; profile=none; digest=") {
|
|
t.Fatalf("validate output = %q", validateOut.String())
|
|
}
|
|
|
|
var showOut bytes.Buffer
|
|
if err := ConfigShow(context.Background(), []string{"--config", pipelinePath}, &showOut); err != nil {
|
|
t.Fatalf("ConfigShow() error = %v", err)
|
|
}
|
|
show := showOut.String()
|
|
if !strings.HasSuffix(show, "\n") || !strings.Contains(show, "workspace:\n") || !strings.Contains(show, "root: "+workspaceRoot) {
|
|
t.Fatalf("show output = %q", show)
|
|
}
|
|
if strings.Contains(show, "artifact_families") || strings.Contains(show, "resolution") {
|
|
t.Fatalf("show output leaked resolution-only fields: %q", show)
|
|
}
|
|
if strings.Contains(show, secret) {
|
|
t.Fatalf("show output leaked a raw secret: %q", show)
|
|
}
|
|
var sourcesOut bytes.Buffer
|
|
if err := ConfigSources(context.Background(), []string{"--config", pipelinePath}, &sourcesOut); err != nil {
|
|
t.Fatalf("ConfigSources() error = %v", err)
|
|
}
|
|
if strings.Contains(sourcesOut.String(), secret) {
|
|
t.Fatalf("sources output leaked a raw secret: %q", sourcesOut.String())
|
|
}
|
|
writeInspectionProfiles(t, pipelinePath, "whisperx:\n language: en\n", "whisperx:\n language: fr\n")
|
|
var diffOut bytes.Buffer
|
|
if err := ConfigDiff(context.Background(), []string{"production", "testing", "--config", pipelinePath}, &diffOut); err != nil {
|
|
t.Fatalf("ConfigDiff() error = %v", err)
|
|
}
|
|
if strings.Contains(diffOut.String(), secret) {
|
|
t.Fatalf("diff output leaked a raw secret: %q", diffOut.String())
|
|
}
|
|
if calls != 0 {
|
|
t.Fatalf("inspection invoked configured external endpoint %d time(s)", calls)
|
|
}
|
|
if _, err := os.Stat(workspaceRoot); !os.IsNotExist(err) {
|
|
t.Fatalf("workspace root stat error = %v, want absent", err)
|
|
}
|
|
}
|
|
|
|
func TestConfigDiffReportsSemanticProfileChanges(t *testing.T) {
|
|
workspaceRoot := t.TempDir()
|
|
pipelinePath, _, _ := writeValidConfigFiles(t, workspaceRoot)
|
|
writeInspectionProfiles(t, pipelinePath, `workspace:
|
|
cleanup_after_publish: true
|
|
whisperx:
|
|
language: en
|
|
audita:
|
|
modules: [glossary, grammar]
|
|
scriptorium:
|
|
artifacts:
|
|
production_only:
|
|
enabled: false
|
|
output_path: artifacts/production.md
|
|
`, `workspace:
|
|
cleanup_after_publish: false
|
|
whisperx:
|
|
language: fr
|
|
audita:
|
|
modules: []
|
|
scriptorium:
|
|
artifacts:
|
|
testing_only:
|
|
enabled: false
|
|
output_path: artifacts/testing.md
|
|
`)
|
|
|
|
args := []string{"production", "testing", "--config", pipelinePath}
|
|
var first, second bytes.Buffer
|
|
if err := ConfigDiff(context.Background(), args, &first); err != nil {
|
|
t.Fatalf("ConfigDiff() error = %v", err)
|
|
}
|
|
if err := ConfigDiff(context.Background(), args, &second); err != nil {
|
|
t.Fatalf("second ConfigDiff() error = %v", err)
|
|
}
|
|
if first.String() != second.String() {
|
|
t.Fatalf("diff output is not deterministic:\nfirst=%q\nsecond=%q", first.String(), second.String())
|
|
}
|
|
output := first.String()
|
|
for _, want := range []string{
|
|
"changed\taudita.modules\t[\"glossary\",\"grammar\"]\t[]\n",
|
|
"changed\tworkspace.cleanup_after_publish\ttrue\tfalse\n",
|
|
"changed\twhisperx.language\t\"en\"\t\"fr\"\n",
|
|
"removed\tscriptorium.artifacts.production_only.enabled\tfalse\n",
|
|
"added\tscriptorium.artifacts.testing_only.enabled\tfalse\n",
|
|
} {
|
|
if !strings.Contains(output, want) {
|
|
t.Fatalf("diff output missing %q:\n%s", want, output)
|
|
}
|
|
}
|
|
if strings.Index(output, "audita.modules") > strings.Index(output, "workspace.cleanup_after_publish") {
|
|
t.Fatalf("diff records are not sorted by path:\n%s", output)
|
|
}
|
|
var reversed bytes.Buffer
|
|
if err := ConfigDiff(context.Background(), []string{"testing", "production", "--config", pipelinePath}, &reversed); err != nil {
|
|
t.Fatalf("reversed ConfigDiff() error = %v", err)
|
|
}
|
|
if !strings.Contains(reversed.String(), "changed\twhisperx.language\t\"fr\"\t\"en\"\n") {
|
|
t.Fatalf("reversed diff did not independently resolve profiles:\n%s", reversed.String())
|
|
}
|
|
}
|
|
|
|
func TestConfigDiffComparesExpandedFamiliesAndPublishRules(t *testing.T) {
|
|
pipelinePath, campaignPath := writeInspectionFamilyConfig(t)
|
|
writeInspectionProfiles(t, pipelinePath, `scriptorium:
|
|
artifact_families:
|
|
character_note:
|
|
enabled: false
|
|
member_vars:
|
|
character_name: character.name
|
|
publish:
|
|
enabled: true
|
|
required: false
|
|
`, `scriptorium:
|
|
artifact_families:
|
|
character_note:
|
|
enabled: true
|
|
prompt_id: dnd.character_note
|
|
member_vars:
|
|
character_name: character.class_summary
|
|
publish:
|
|
enabled: true
|
|
required: true
|
|
`)
|
|
|
|
var out bytes.Buffer
|
|
if err := ConfigDiff(context.Background(), []string{
|
|
"production", "testing", "--config", pipelinePath, "--campaign-file", campaignPath,
|
|
}, &out); err != nil {
|
|
t.Fatalf("ConfigDiff() error = %v", err)
|
|
}
|
|
output := out.String()
|
|
for _, want := range []string{
|
|
"changed\tscriptorium.artifacts.character_note_arannis.enabled\tfalse\ttrue\n",
|
|
"changed\tscriptorium.artifacts.character_note_arannis.vars.character_name\t\"Arannis\"\t\"wizard\"\n",
|
|
"changed\tpublish.outputs\t",
|
|
} {
|
|
if !strings.Contains(output, want) {
|
|
t.Fatalf("family diff output missing %q:\n%s", want, output)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConfigDiffReportsEqualityAndRejectsInvalidInput(t *testing.T) {
|
|
workspaceRoot := t.TempDir()
|
|
pipelinePath, campaignPath, _ := writeValidConfigFiles(t, workspaceRoot)
|
|
writeInspectionProfiles(t, pipelinePath, "whisperx:\n language: en\n", "whisperx:\n language: en\n")
|
|
|
|
var equal bytes.Buffer
|
|
if err := ConfigDiff(context.Background(), []string{"production", "testing", "--config", pipelinePath}, &equal); err != nil {
|
|
t.Fatalf("ConfigDiff() equal profiles error = %v", err)
|
|
}
|
|
if got := equal.String(); got != "no differences\n" {
|
|
t.Fatalf("equal diff output = %q", got)
|
|
}
|
|
|
|
for _, args := range [][]string{
|
|
{"production", "testing", "extra", "--config", pipelinePath},
|
|
{"production", "--config", pipelinePath},
|
|
{"production", "production", "--config", pipelinePath},
|
|
{"unknown", "testing", "--config", pipelinePath},
|
|
{"production", "testing", "--config", pipelinePath, "--profile", "production"},
|
|
{"production", "testing", "--config", pipelinePath, "--config", pipelinePath},
|
|
{"production", "testing", "--config", pipelinePath, "--campaign", "sample-campaign", "--campaign-file", campaignPath},
|
|
} {
|
|
if err := ConfigDiff(context.Background(), args, io.Discard); err == nil {
|
|
t.Fatalf("ConfigDiff(%q) succeeded, want error", args)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConfigCommandsInspectMaintainedSplitBundleWithoutRuntimeState(t *testing.T) {
|
|
examplesDir := filepath.Join("..", "..", "examples")
|
|
pipelinePath := filepath.Join(examplesDir, "production-testing", "pipeline.yml")
|
|
campaignPath := filepath.Join(examplesDir, "campaigns", "sample-campaign", "campaign.yml")
|
|
workspacePath := filepath.Join(examplesDir, "production-testing", "workspace")
|
|
if _, err := os.Stat(workspacePath); !os.IsNotExist(err) {
|
|
t.Fatalf("example workspace stat = %v, want absent", err)
|
|
}
|
|
|
|
for _, command := range []func(context.Context, []string, io.Writer) error{ConfigValidate, ConfigShow, ConfigSources} {
|
|
if err := command(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath, "--profile", "production"}, io.Discard); err != nil {
|
|
t.Fatalf("inspection command %T error = %v", command, err)
|
|
}
|
|
}
|
|
var diff bytes.Buffer
|
|
if err := ConfigDiff(context.Background(), []string{"production", "testing", "--config", pipelinePath, "--campaign-file", campaignPath}, &diff); err != nil {
|
|
t.Fatalf("ConfigDiff() error = %v", err)
|
|
}
|
|
if !strings.Contains(diff.String(), "audita.model") {
|
|
t.Fatalf("split bundle profile diff = %q, want model change", diff.String())
|
|
}
|
|
if _, err := os.Stat(workspacePath); !os.IsNotExist(err) {
|
|
t.Fatalf("inspection created example workspace: %v", err)
|
|
}
|
|
}
|
|
|
|
func writeInspectionProfiles(t *testing.T, pipelinePath, production, testing string) {
|
|
t.Helper()
|
|
data, err := os.ReadFile(pipelinePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
composition := "composition:\n default_profile: production\n profiles:\n production:\n overlay: production.yml\n testing:\n overlay: testing.yml\n"
|
|
if err := os.WriteFile(pipelinePath, append([]byte(composition), data...), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
dir := filepath.Dir(pipelinePath)
|
|
mustWriteTestFile(t, filepath.Join(dir, "production.yml"), production)
|
|
mustWriteTestFile(t, filepath.Join(dir, "testing.yml"), testing)
|
|
}
|
|
|
|
func TestConfigCommandsSelectProfilesAndCampaigns(t *testing.T) {
|
|
workspaceRoot := t.TempDir()
|
|
pipelinePath, campaignPath, _ := writeValidConfigFiles(t, workspaceRoot)
|
|
enableCommandTestProfiles(t, pipelinePath)
|
|
|
|
var defaultOut bytes.Buffer
|
|
if err := ConfigValidate(context.Background(), []string{"--config", pipelinePath}, &defaultOut); err != nil {
|
|
t.Fatalf("default ConfigValidate() error = %v", err)
|
|
}
|
|
if !strings.Contains(defaultOut.String(), "profile=production") {
|
|
t.Fatalf("default output = %q", defaultOut.String())
|
|
}
|
|
|
|
var explicitOut bytes.Buffer
|
|
if err := ConfigShow(context.Background(), []string{"--config", pipelinePath, "--profile", "testing"}, &explicitOut); err != nil {
|
|
t.Fatalf("explicit ConfigShow() error = %v", err)
|
|
}
|
|
if !strings.Contains(explicitOut.String(), "language: fr") {
|
|
t.Fatalf("explicit show output = %q", explicitOut.String())
|
|
}
|
|
|
|
for _, args := range [][]string{
|
|
{"--config", pipelinePath, "--campaign", "sample-campaign"},
|
|
{"--config", pipelinePath, "--campaign-file", campaignPath},
|
|
} {
|
|
var out bytes.Buffer
|
|
if err := ConfigValidate(context.Background(), args, &out); err != nil {
|
|
t.Fatalf("ConfigValidate(%q) error = %v", args, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConfigCommandsExpandFamiliesAndRequireCampaign(t *testing.T) {
|
|
pipelinePath, campaignPath := writeInspectionFamilyConfig(t)
|
|
|
|
for _, command := range []func(context.Context, []string, io.Writer) error{ConfigValidate, ConfigShow} {
|
|
var out bytes.Buffer
|
|
err := command(context.Background(), []string{"--config", pipelinePath}, &out)
|
|
if err == nil || !strings.Contains(err.Error(), "artifact_families requires a campaign") {
|
|
t.Fatalf("family command without campaign error = %v", err)
|
|
}
|
|
}
|
|
|
|
var show bytes.Buffer
|
|
if err := ConfigShow(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath}, &show); err != nil {
|
|
t.Fatalf("ConfigShow() error = %v", err)
|
|
}
|
|
if !strings.Contains(show.String(), "character_note_arannis:") || strings.Contains(show.String(), "artifact_families") {
|
|
t.Fatalf("expanded show output = %q", show.String())
|
|
}
|
|
|
|
loadedPipeline, err := config.LoadPipeline(pipelinePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
loadedCampaign, err := config.LoadCampaign(campaignPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
loaded, err := config.LoadPipelineCampaign(pipelinePath, loadedPipeline, campaignPath, loadedCampaign)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var validateOut bytes.Buffer
|
|
if err := ConfigValidate(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath}, &validateOut); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(validateOut.String(), "digest="+config.EffectivePipelineDigest(loaded.Pipeline)) {
|
|
t.Fatalf("inspection digest = %q, want %q", validateOut.String(), config.EffectivePipelineDigest(loaded.Pipeline))
|
|
}
|
|
}
|
|
|
|
func TestConfigValidateReportsCanonicalPartyAndImportErrors(t *testing.T) {
|
|
pipelinePath, campaignPath := writeInspectionFamilyConfig(t)
|
|
mustWriteTestFile(t, filepath.Join(filepath.Dir(campaignPath), "party.yml"), "schema_version: narratio.party.v2\ncharacters: {}\n")
|
|
if err := ConfigValidate(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath}, io.Discard); err == nil || !strings.Contains(err.Error(), "unsupported") {
|
|
t.Fatalf("canonical party error = %v", err)
|
|
}
|
|
|
|
dir := t.TempDir()
|
|
rootPath := filepath.Join(dir, "pipeline.yml")
|
|
mustWriteTestFile(t, rootPath, `composition:
|
|
imports: [conf.yml]
|
|
workspace:
|
|
root: /one
|
|
whisperx:
|
|
transcribe_url: https://transcription.example.com/transcribe
|
|
`)
|
|
mustWriteTestFile(t, filepath.Join(dir, "conf.yml"), "workspace:\n root: /two\n")
|
|
err := ConfigValidate(context.Background(), []string{"--config", rootPath}, io.Discard)
|
|
if err == nil || !strings.Contains(err.Error(), "workspace.root") || !strings.Contains(err.Error(), "pipeline.yml") || !strings.Contains(err.Error(), "conf.yml") {
|
|
t.Fatalf("import diagnostic = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestConfigSourcesReportsStableOwnership(t *testing.T) {
|
|
workspaceRoot := t.TempDir()
|
|
pipelinePath, campaignPath, _ := writeValidConfigFiles(t, workspaceRoot)
|
|
enableCommandTestProfiles(t, pipelinePath)
|
|
|
|
args := []string{"--config", pipelinePath, "--campaign-file", campaignPath, "--profile", "testing"}
|
|
var first, second bytes.Buffer
|
|
if err := ConfigSources(context.Background(), args, &first); err != nil {
|
|
t.Fatalf("first ConfigSources() error = %v", err)
|
|
}
|
|
if err := ConfigSources(context.Background(), args, &second); err != nil {
|
|
t.Fatalf("second ConfigSources() error = %v", err)
|
|
}
|
|
if first.String() != second.String() {
|
|
t.Fatalf("sources output is not deterministic:\nfirst=%q\nsecond=%q", first.String(), second.String())
|
|
}
|
|
output := first.String()
|
|
for _, want := range []string{
|
|
"root: ",
|
|
"imports: none",
|
|
"profile: name=testing selection=cli overlay=",
|
|
"campaign: id=sample-campaign source=",
|
|
"party: mode=legacy source=",
|
|
"digest: ",
|
|
"path\trole\tsource\n",
|
|
"workspace.root\troot\t",
|
|
"whisperx.language\tprofile\t",
|
|
"campaign.inputs.players_file\tlegacy_player\t",
|
|
"trim.enabled\tdefault\tdefault",
|
|
} {
|
|
if !strings.Contains(output, want) {
|
|
t.Fatalf("sources output missing %q:\n%s", want, output)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConfigSourcesReportsCanonicalFamilyAndPublishOrigins(t *testing.T) {
|
|
pipelinePath, campaignPath := writeInspectionFamilyConfig(t)
|
|
var out bytes.Buffer
|
|
if err := ConfigSources(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath}, &out); err != nil {
|
|
t.Fatalf("ConfigSources() error = %v", err)
|
|
}
|
|
output := out.String()
|
|
partyPath := filepath.Join(filepath.Dir(campaignPath), "party.yml")
|
|
for _, want := range []string{
|
|
"party: mode=canonical source=" + partyPath,
|
|
"derived.players\tparty\t" + partyPath,
|
|
"scriptorium.artifacts.character_note_arannis.enabled\tfamily\t" + pipelinePath,
|
|
"scriptorium.artifacts.character_note_arannis.enabled\tparty\t" + partyPath,
|
|
"scriptorium.artifacts.character_note_arannis.depends_on\tfamily\t" + pipelinePath,
|
|
"scriptorium.artifacts.character_note_arannis.inputs.prior.source\tparty\t" + partyPath,
|
|
"publish.outputs[",
|
|
"\tfamily\t" + pipelinePath,
|
|
"\tparty\t" + partyPath,
|
|
} {
|
|
if !strings.Contains(output, want) {
|
|
t.Fatalf("sources output missing %q:\n%s", want, output)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConfigSourcesPreservesProfileOwnershipThroughFamilyExpansion(t *testing.T) {
|
|
pipelinePath, campaignPath := writeInspectionFamilyConfig(t)
|
|
data, err := os.ReadFile(pipelinePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
profilePath := filepath.Join(filepath.Dir(pipelinePath), "testing.yml")
|
|
composition := "composition:\n default_profile: testing\n profiles:\n testing:\n overlay: testing.yml\n"
|
|
if err := os.WriteFile(pipelinePath, append([]byte(composition), data...), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
mustWriteTestFile(t, profilePath, `scriptorium:
|
|
artifact_families:
|
|
character_note:
|
|
enabled: true
|
|
prompt_id: dnd.character_note
|
|
`)
|
|
|
|
var out bytes.Buffer
|
|
if err := ConfigSources(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath}, &out); err != nil {
|
|
t.Fatalf("ConfigSources() error = %v", err)
|
|
}
|
|
want := "scriptorium.artifacts.character_note_arannis.enabled\tfamily\t" + profilePath
|
|
if !strings.Contains(out.String(), want) {
|
|
t.Fatalf("sources output missing profile-generated ownership %q:\n%s", want, out.String())
|
|
}
|
|
}
|
|
|
|
func TestConfigSourcesReportsRootImportProfileAndDefaultOwnership(t *testing.T) {
|
|
dir := t.TempDir()
|
|
rootPath := filepath.Join(dir, "pipeline.yml")
|
|
importPath := filepath.Join(dir, "base.yml")
|
|
profilePath := filepath.Join(dir, "testing.yml")
|
|
mustWriteTestFile(t, rootPath, `composition:
|
|
imports: [base.yml]
|
|
default_profile: testing
|
|
profiles:
|
|
testing:
|
|
overlay: testing.yml
|
|
workspace:
|
|
root: /srv/narratio
|
|
whisperx:
|
|
transcribe_url: https://transcription.example.com/transcribe
|
|
`)
|
|
mustWriteTestFile(t, importPath, "storage:\n backend: local\n")
|
|
mustWriteTestFile(t, profilePath, "whisperx:\n language: fr\n")
|
|
|
|
var out bytes.Buffer
|
|
if err := ConfigSources(context.Background(), []string{"--config", rootPath}, &out); err != nil {
|
|
t.Fatalf("ConfigSources() error = %v", err)
|
|
}
|
|
output := out.String()
|
|
for _, want := range []string{
|
|
"import: " + importPath,
|
|
"profile: name=testing selection=default overlay=" + profilePath,
|
|
"workspace.root\troot\t" + rootPath,
|
|
"storage.backend\timport\t" + importPath,
|
|
"whisperx.language\tprofile\t" + profilePath,
|
|
"trim.enabled\tdefault\tdefault",
|
|
} {
|
|
if !strings.Contains(output, want) {
|
|
t.Fatalf("sources output missing %q:\n%s", want, output)
|
|
}
|
|
}
|
|
}
|
|
|
|
func writeInspectionFamilyConfig(t *testing.T) (string, string) {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
campaignRoot := filepath.Join(dir, "campaigns")
|
|
campaignDir := filepath.Join(campaignRoot, "sample-campaign")
|
|
pipelinePath := filepath.Join(dir, "pipeline.yml")
|
|
campaignPath := filepath.Join(campaignDir, "campaign.yml")
|
|
mustWriteTestFile(t, pipelinePath, `workspace:
|
|
root: `+filepath.Join(dir, "workspace")+`
|
|
campaigns:
|
|
root: `+campaignRoot+`
|
|
whisperx:
|
|
transcribe_url: https://transcription.example.com/transcribe
|
|
scriptorium:
|
|
artifact_families:
|
|
character_meta:
|
|
enabled: false
|
|
for_each: party.characters
|
|
output_path_pattern: artifacts/characters/{character_id}/meta.md
|
|
character_note:
|
|
enabled: false
|
|
for_each: party.characters
|
|
output_path_pattern: artifacts/characters/{character_id}/note.md
|
|
member_dependencies: [character_meta]
|
|
inputs:
|
|
prior: {source: narratio.member_artifact.character_meta, required: true}
|
|
member_vars:
|
|
character_name: character.name
|
|
publish:
|
|
enabled: true
|
|
required: true
|
|
publish:
|
|
enabled: true
|
|
upload_run: false
|
|
`)
|
|
mustWriteTestFile(t, campaignPath, `campaign_id: sample-campaign
|
|
inputs:
|
|
speakers_file: ./speakers.yml
|
|
autocorrect_file: ./autocorrect.yml
|
|
glossary_file: ./glossary.yml
|
|
party_file: ./party.yml
|
|
`)
|
|
mustWriteTestFile(t, filepath.Join(campaignDir, "party.yml"), `schema_version: narratio.party.v1
|
|
characters:
|
|
arannis:
|
|
player: {name: Eric}
|
|
character: {name: Arannis, classes: [{name: wizard}]}
|
|
`)
|
|
return pipelinePath, campaignPath
|
|
}
|