Validate ConfigKit pipeline documents
This commit is contained in:
197
internal/core/config/pipeline_document_test.go
Normal file
197
internal/core/config/pipeline_document_test.go
Normal file
@@ -0,0 +1,197 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||
)
|
||||
|
||||
func TestDocumentPipelineNormalizesCanonicalIdentifiers(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
loaded, err := loadDocumentSource(configkit.Bytes("document.yml", []byte(`version: 5
|
||||
pipelines:
|
||||
" session ":
|
||||
llm_profile: " local "
|
||||
input:
|
||||
module: " seriatim "
|
||||
artifacts:
|
||||
" spells ":
|
||||
extract:
|
||||
module: " dnd/spells "
|
||||
structured_output_repair_attempts: 0
|
||||
validators: []
|
||||
merge:
|
||||
module: dnd/merge
|
||||
references:
|
||||
previous:
|
||||
artifact:
|
||||
step: " default "
|
||||
lane: " spells "
|
||||
`)), LoadOptions{})
|
||||
if err != nil {
|
||||
var loadError *configkit.LoadError
|
||||
if errors.As(err, &loadError) {
|
||||
t.Fatalf("loadDocumentSource() diagnostics = %#v", loadError.Diagnostics())
|
||||
}
|
||||
t.Fatalf("loadDocumentSource() error = %v", err)
|
||||
}
|
||||
profile, ok := loaded.Config.Pipelines["session"]
|
||||
if !ok || profile.Input.Module != "seriatim" || profile.LLMProfile == nil || *profile.LLMProfile != "local" {
|
||||
t.Fatalf("normalized pipeline = %#v", loaded.Config.Pipelines)
|
||||
}
|
||||
lane, ok := profile.Artifacts["spells"]
|
||||
if !ok || lane.Extract.StructuredOutputRepairAttempts == nil || *lane.Extract.StructuredOutputRepairAttempts != 0 || lane.Extract.Validators == nil || len(lane.Extract.Validators) != 0 {
|
||||
t.Fatalf("normalized lane = %#v", profile.Artifacts)
|
||||
}
|
||||
selector := lane.Merge.References["previous"].Artifact
|
||||
if selector == nil || selector.Step != "default" || selector.Lane != "spells" {
|
||||
t.Fatalf("artifact selector = %#v", selector)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDocumentPipelineRejectsInvalidShapes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
source string
|
||||
path string
|
||||
}{
|
||||
{
|
||||
name: "both pipeline forms",
|
||||
source: `version: 5
|
||||
pipelines:
|
||||
session:
|
||||
input: {module: seriatim}
|
||||
artifacts: {}
|
||||
steps:
|
||||
- id: first
|
||||
artifacts: {}
|
||||
`,
|
||||
path: "/pipelines/session/steps",
|
||||
},
|
||||
{
|
||||
name: "empty ordered steps",
|
||||
source: `version: 5
|
||||
pipelines:
|
||||
session:
|
||||
input: {module: seriatim}
|
||||
steps: []
|
||||
`,
|
||||
path: "/pipelines/session/steps",
|
||||
},
|
||||
{
|
||||
name: "normalized pipeline collision",
|
||||
source: `version: 5
|
||||
pipelines:
|
||||
session: {input: {module: seriatim}}
|
||||
" session ": {input: {module: seriatim}}
|
||||
`,
|
||||
path: "/pipelines/session",
|
||||
},
|
||||
{
|
||||
name: "duplicate lane across ordered steps",
|
||||
source: `version: 5
|
||||
pipelines:
|
||||
session:
|
||||
input: {module: seriatim}
|
||||
steps:
|
||||
- id: first
|
||||
artifacts: {summary: {extract: {module: dnd/summary}}}
|
||||
- id: second
|
||||
artifacts: {summary: {extract: {module: dnd/summary}}}
|
||||
`,
|
||||
path: "/pipelines/session/steps/1/artifacts/summary",
|
||||
},
|
||||
{
|
||||
name: "invalid reference union",
|
||||
source: `version: 5
|
||||
pipelines:
|
||||
session:
|
||||
input: {module: seriatim}
|
||||
references:
|
||||
party: {path: ./party.txt, artifact: {step: one, lane: summary}}
|
||||
`,
|
||||
path: "/pipelines/session/references/party",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
_, err := loadDocumentSource(configkit.Bytes("document.yml", []byte(test.source)), LoadOptions{})
|
||||
assertDocumentDiagnosticAt(t, err, test.path)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDocumentPipelineRejectsInvalidBindingPlacementAndPresence(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
source string
|
||||
path string
|
||||
}{
|
||||
{
|
||||
name: "input validators",
|
||||
source: `version: 5
|
||||
pipelines:
|
||||
session:
|
||||
input:
|
||||
module: seriatim
|
||||
validators: [{module: generic/valid_json}]
|
||||
`,
|
||||
path: "/pipelines/session/input/validators",
|
||||
},
|
||||
{
|
||||
name: "blank selected profile",
|
||||
source: `version: 5
|
||||
pipelines:
|
||||
session:
|
||||
llm_profile: " "
|
||||
input: {module: seriatim}
|
||||
`,
|
||||
path: "/pipelines/session/llm_profile",
|
||||
},
|
||||
{
|
||||
name: "null validators",
|
||||
source: `version: 5
|
||||
pipelines:
|
||||
session:
|
||||
input: {module: seriatim}
|
||||
chunk: {module: generic/chunk, validators: null}
|
||||
`,
|
||||
path: "/pipelines/session/chunk/validators",
|
||||
},
|
||||
{
|
||||
name: "negative retry budget",
|
||||
source: `version: 5
|
||||
pipelines:
|
||||
session:
|
||||
input: {module: seriatim, retries: -1}
|
||||
`,
|
||||
path: "/pipelines/session/input/retries",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
_, err := loadDocumentSource(configkit.Bytes("document.yml", []byte(test.source)), LoadOptions{})
|
||||
assertDocumentDiagnosticAt(t, err, test.path)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func assertDocumentDiagnosticAt(t *testing.T, err error, path string) {
|
||||
t.Helper()
|
||||
var loadError *configkit.LoadError
|
||||
if !errors.As(err, &loadError) {
|
||||
t.Fatalf("error = %v, want ConfigKit load error", err)
|
||||
}
|
||||
for _, diagnostic := range loadError.Diagnostics() {
|
||||
if diagnostic.Path.String() == path {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatalf("diagnostics = %#v, want a diagnostic at %s", loadError.Diagnostics(), path)
|
||||
}
|
||||
Reference in New Issue
Block a user