Resolve corresponding artifact family dependencies
This commit is contained in:
@@ -188,6 +188,115 @@ func TestArtifactFamiliesRejectGeneratedKeyAndOutputCollisions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestArtifactFamiliesExpandSameMemberDependenciesAndInputs(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writePartyResolutionFile(t, filepath.Join(dir, "party.yml"), `schema_version: narratio.party.v1
|
||||
characters:
|
||||
arannis:
|
||||
player: {name: Eric}
|
||||
character: {name: Arannis, classes: [{name: wizard}]}
|
||||
bryn:
|
||||
player: {name: Bri}
|
||||
character: {name: Bryn, classes: [{name: fighter}]}
|
||||
`)
|
||||
families := `
|
||||
character_meta:
|
||||
enabled: true
|
||||
for_each: party.characters
|
||||
prompt_id: dnd.character_meta
|
||||
output_path_pattern: artifacts/characters/{character_id}/meta.md
|
||||
character_items:
|
||||
enabled: true
|
||||
for_each: party.characters
|
||||
prompt_id: dnd.character_items
|
||||
output_path_pattern: artifacts/characters/{character_id}/items.md
|
||||
depends_on: [session_recap]
|
||||
member_dependencies: [character_meta]
|
||||
inputs:
|
||||
transcript: {source: narratio.transcript.final_trimmed, required: true}
|
||||
prior_meta: {source: narratio.member_artifact.character_meta, required: true}
|
||||
`
|
||||
pipelinePath, campaignPath, sessionPath := writeArtifactFamilyConfig(t, dir, strings.Replace(artifactFamilyPipelineYAML(families), " artifact_families:", " artifacts:\n session_recap:\n enabled: false\n output_path: artifacts/session_recap.md\n artifact_families:", 1))
|
||||
cfg, err := LoadWithSessionOptions(pipelinePath, campaignPath, sessionPath, SessionLoadOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
items := cfg.Pipeline.Scriptorium.Artifacts["character_items_arannis"]
|
||||
if !reflect.DeepEqual(items.DependsOn, []string{"session_recap", "character_meta_arannis"}) {
|
||||
t.Fatalf("member dependencies = %#v", items.DependsOn)
|
||||
}
|
||||
if got := items.Inputs["prior_meta"].Source; got != "narratio.artifact.character_meta_arannis" {
|
||||
t.Fatalf("rewritten member source = %q", got)
|
||||
}
|
||||
catalog := ArtifactFamilies(cfg.Pipeline)
|
||||
if got := catalog.Members["character_items_arannis"]; !reflect.DeepEqual(got.Dependencies, items.DependsOn) || got.Inputs["prior_meta"] != "narratio.artifact.character_meta_arannis" {
|
||||
t.Fatalf("member provenance = %#v", got)
|
||||
}
|
||||
for key, artifact := range cfg.Pipeline.Scriptorium.Artifacts {
|
||||
for name, input := range artifact.Inputs {
|
||||
if strings.Contains(input.Source, "narratio.member_artifact.") {
|
||||
t.Fatalf("unresolved source at %s.%s = %q", key, name, input.Source)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestArtifactFamiliesRejectInvalidMemberDependenciesAndSources(t *testing.T) {
|
||||
for _, test := range []struct{ name, families, want string }{
|
||||
{name: "missing family", families: strings.Replace(validFamilyYAML, "member_vars:", "member_dependencies: [missing]\n member_vars:", 1), want: "unknown family"},
|
||||
{name: "self dependency", families: strings.Replace(validFamilyYAML, "member_vars:", "member_dependencies: [character_meta]\n member_vars:", 1), want: "must not reference its own family"},
|
||||
{name: "duplicate dependency", families: strings.Replace(validFamilyYAML, "member_vars:", "member_dependencies: [other, other]\n member_vars:", 1) + `
|
||||
other:
|
||||
for_each: party.characters
|
||||
output_path_pattern: artifacts/characters/{character_id}/other.md
|
||||
`, want: "duplicates family"},
|
||||
{name: "undeclared source dependency", families: strings.Replace(validFamilyYAML, "member_vars:", "inputs:\n prior: {source: narratio.member_artifact.other, required: true}\n member_vars:", 1) + `
|
||||
other:
|
||||
for_each: party.characters
|
||||
output_path_pattern: artifacts/characters/{character_id}/other.md
|
||||
`, want: "requires member_dependencies"},
|
||||
{name: "transitive cycle", families: strings.Replace(validFamilyYAML, "member_vars:", "member_dependencies: [other]\n member_vars:", 1) + `
|
||||
other:
|
||||
for_each: party.characters
|
||||
output_path_pattern: artifacts/characters/{character_id}/other.md
|
||||
member_dependencies: [character_meta]
|
||||
`, want: "dependencies must not contain cycles"},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writePartyResolutionFile(t, filepath.Join(dir, "party.yml"), canonicalPartyFixture)
|
||||
pipelinePath, campaignPath, sessionPath := writeArtifactFamilyConfig(t, dir, artifactFamilyPipelineYAML(test.families))
|
||||
_, err := LoadWithSessionOptions(pipelinePath, campaignPath, sessionPath, SessionLoadOptions{})
|
||||
if err == nil || !strings.Contains(err.Error(), test.want) {
|
||||
t.Fatalf("error = %v, want %q", err, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pipeline := &PipelineConfig{
|
||||
Scriptorium: &ScriptoriumConfig{Artifacts: map[string]ScriptoriumArtifactConfig{
|
||||
"explicit": {Inputs: map[string]ScriptoriumInputConfig{
|
||||
"bad": {Source: "narratio.member_artifact.character_meta"},
|
||||
}},
|
||||
}},
|
||||
resolution: &pipelineResolutionMetadata{artifactFamilies: map[string]ScriptoriumArtifactFamilyConfig{
|
||||
"character_meta": {ForEach: partyCharactersFamilySource, OutputPathPattern: "artifacts/{character_id}.md"},
|
||||
}},
|
||||
}
|
||||
document, err := ParseParty([]byte(canonicalPartyFixture))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := expandPipelineArtifactFamilies(pipeline, ResolvedParty{Mode: PartyModeCanonical, Canonical: document.Canonical}); err == nil || !strings.Contains(err.Error(), "outside an artifact family") {
|
||||
t.Fatalf("concrete member source error = %v", err)
|
||||
}
|
||||
pipeline.Scriptorium.Artifacts["explicit"] = ScriptoriumArtifactConfig{Inputs: map[string]ScriptoriumInputConfig{"bad": {Source: "narratio.member_artifact."}}}
|
||||
pipeline.resolution.artifactFamiliesExpanded = false
|
||||
if err := expandPipelineArtifactFamilies(pipeline, ResolvedParty{Mode: PartyModeCanonical, Canonical: document.Canonical}); err == nil || !strings.Contains(err.Error(), "malformed member artifact source") {
|
||||
t.Fatalf("malformed concrete member source error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
const validFamilyYAML = `
|
||||
character_meta:
|
||||
enabled: true
|
||||
|
||||
Reference in New Issue
Block a user