Files
notarius/internal/core/config/inheritance_test.go

134 lines
4.1 KiB
Go

package config
import (
"testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
)
func TestPipelineInheritancePreservesCompositionAndReplacesSteps(t *testing.T) {
t.Parallel()
tests := []struct {
name string
childSteps string
wantStepIDs []string
}{
{
name: "inherits ordered steps",
wantStepIDs: []string{"prepare", "summarize"},
},
{
name: "replaces ordered steps",
childSteps: `
steps:
- id: replacement
artifacts:
summary:
extract: {module: extract}`,
wantStepIDs: []string{"replacement"},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
source := `version: 5
pipelines:
parent:
input: {module: input}
structured_output_repair_attempts: 2
steps:
- id: prepare
artifacts:
score:
extract: {module: extract, retries: 2}
- id: summarize
artifacts:
notes:
extract: {module: extract}
child:
extends: parent
llm_profile: local
structured_output_repair_attempts: 0` + test.childSteps + "\n"
loaded, err := loadConfigSource(configkit.Bytes("inheritance.yml", []byte(source)), LoadOptions{})
if err != nil {
t.Fatalf("loadConfigSource() error = %v", err)
}
parent := loaded.Config.Pipelines["parent"]
child := loaded.Config.Pipelines["child"]
if parent.Input.Module != "input" || child.Input.Module != "input" {
t.Fatalf("parent/child inputs = %#v / %#v", parent.Input, child.Input)
}
if child.LLMProfile != "local" ||
child.StructuredOutputRepairAttempts == nil || *child.StructuredOutputRepairAttempts != 0 {
t.Fatalf("child overrides = %#v", child)
}
if parent.StructuredOutputRepairAttempts == nil || *parent.StructuredOutputRepairAttempts != 2 {
t.Fatalf("parent settings changed: %#v", parent)
}
if len(child.Steps) != len(test.wantStepIDs) {
t.Fatalf("child steps = %#v, want %v", child.Steps, test.wantStepIDs)
}
for i, want := range test.wantStepIDs {
if child.Steps[i].ID != want {
t.Fatalf("child step %d = %q, want %q", i, child.Steps[i].ID, want)
}
}
if test.childSteps == "" && child.Steps[0].Artifacts["score"].Extract.Module != "extract" {
t.Fatalf("inherited first artifact = %#v", child.Steps[0].Artifacts["score"])
}
for _, id := range []string{"parent", "child"} {
resolved, err := loaded.Config.Resolve(ResolveInput{PipelineID: id, Catalog: effectiveCatalog(t)})
if err != nil {
t.Fatalf("Resolve(%q) error = %v", id, err)
}
if resolved.ResolvedPipeline.ID != id {
t.Fatalf("resolved pipeline ID = %q, want %q", resolved.ResolvedPipeline.ID, id)
}
wantResolvedSteps := len(test.wantStepIDs)
if id == "parent" {
wantResolvedSteps = 2
}
if len(resolved.ResolvedPipeline.Steps) != wantResolvedSteps {
t.Fatalf("resolved %q steps = %#v", id, resolved.ResolvedPipeline.Steps)
}
if id == "child" && resolved.ResolvedPipeline.Steps[0].ArtifactLanes[0].Extract.LLMProfile != "local" {
t.Fatalf("resolved child profile = %q", resolved.ResolvedPipeline.Steps[0].ArtifactLanes[0].Extract.LLMProfile)
}
}
})
}
}
func TestArtifactLaneInheritanceUsesSiblingMappingComposition(t *testing.T) {
t.Parallel()
loaded, err := loadConfigSource(configkit.Bytes("lanes.yml", []byte(`version: 5
pipelines:
session:
input: {module: input}
artifacts:
base:
extract: {module: extract, retries: 2}
derived:
extends: base
extract: {retries: 4}
`)), LoadOptions{})
if err != nil {
t.Fatalf("loadConfigSource() error = %v", err)
}
lanes := loaded.Config.Pipelines["session"].Artifacts
if lanes["base"].Extract.Module != "extract" || lanes["base"].Extract.Retries != 2 {
t.Fatalf("base lane = %#v", lanes["base"])
}
if lanes["derived"].Extract.Module != "extract" || lanes["derived"].Extract.Retries != 4 {
t.Fatalf("derived lane = %#v", lanes["derived"])
}
if _, err := loaded.Config.Resolve(ResolveInput{PipelineID: "session", Catalog: effectiveCatalog(t)}); err != nil {
t.Fatalf("Resolve() error = %v", err)
}
}