Consolidate configuration and resolver tests
This commit is contained in:
@@ -18,109 +18,102 @@ import (
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/modules/seriatim/input/transcript"
|
||||
)
|
||||
|
||||
func TestPipelineConfigLoadsAndResolvesWithDNDSpellsExtractor(t *testing.T) {
|
||||
data, err := os.ReadFile("testdata/pipeline.yml")
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile(pipeline.yml) error = %v, want nil", err)
|
||||
}
|
||||
fileCfg, err := config.ParseFileConfigYAML(data)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseFileConfigYAML() error = %v, want nil", err)
|
||||
func TestDNDSpellCapabilityFailures(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mutate func(pipeline.ModuleSpec, pipeline.ModuleSpec) (pipeline.ModuleSpec, pipeline.ModuleSpec)
|
||||
wantModule string
|
||||
wantCap string
|
||||
}{
|
||||
{
|
||||
name: "spell extractor requires transcript source",
|
||||
mutate: func(input, extractor pipeline.ModuleSpec) (pipeline.ModuleSpec, pipeline.ModuleSpec) {
|
||||
input.Provides = withoutCapability(input.Provides, "source.transcript")
|
||||
return input, extractor
|
||||
},
|
||||
wantModule: spells.Key,
|
||||
wantCap: "source.transcript",
|
||||
},
|
||||
{
|
||||
name: "append-order merger requires spell casts",
|
||||
mutate: func(input, extractor pipeline.ModuleSpec) (pipeline.ModuleSpec, pipeline.ModuleSpec) {
|
||||
extractor.Provides = withoutCapability(extractor.Provides, "dnd.spell_casts")
|
||||
return input, extractor
|
||||
},
|
||||
wantModule: pipeline.DefaultMergeModule,
|
||||
wantCap: "dnd.spell_casts",
|
||||
},
|
||||
}
|
||||
|
||||
cfg := config.Default()
|
||||
if err := cfg.ApplyFileConfig(fileCfg); err != nil {
|
||||
t.Fatalf("ApplyFileConfig() error = %v, want nil", err)
|
||||
}
|
||||
|
||||
resolved, err := cfg.Resolve(config.ResolveInput{
|
||||
PipelineID: "dnd-spells-fixture",
|
||||
Catalog: dndSpellsTestCatalog(t, dndSpellsCatalogSpecs{}),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Resolve() error = %v, want nil", err)
|
||||
}
|
||||
|
||||
if len(resolved.ResolvedPipeline.ArtifactLanes) != 1 {
|
||||
t.Fatalf("len(ArtifactLanes) = %d, want 1", len(resolved.ResolvedPipeline.ArtifactLanes))
|
||||
}
|
||||
lane := resolved.ResolvedPipeline.ArtifactLanes[0]
|
||||
if lane.ID != "spells" {
|
||||
t.Fatalf("lane ID = %q, want spells", lane.ID)
|
||||
}
|
||||
if lane.Extract.Module != spells.Key {
|
||||
t.Fatalf("extract module = %q, want %q", lane.Extract.Module, spells.Key)
|
||||
}
|
||||
if resolved.ResolvedPipeline.Digest == "" {
|
||||
t.Fatal("resolved digest is empty")
|
||||
}
|
||||
|
||||
again, err := cfg.Resolve(config.ResolveInput{
|
||||
PipelineID: "dnd-spells-fixture",
|
||||
Catalog: dndSpellsTestCatalog(t, dndSpellsCatalogSpecs{}),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("second Resolve() error = %v, want nil", err)
|
||||
}
|
||||
if resolved.ResolvedPipeline.Digest != again.ResolvedPipeline.Digest {
|
||||
t.Fatalf("resolved digest = %q, second digest = %q; want stable digest", resolved.ResolvedPipeline.Digest, again.ResolvedPipeline.Digest)
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
inputSpec, extractorSpec := tt.mutate(transcript.ModuleSpec(), spells.ModuleSpec())
|
||||
_, err := pipeline.ResolvePipeline(dndCapabilityProfile(), pipeline.ResolveOptions{}, dndCapabilityCatalog(t, inputSpec, extractorSpec))
|
||||
if err == nil || !strings.Contains(err.Error(), "missing capability") || !strings.Contains(err.Error(), tt.wantCap) || !strings.Contains(err.Error(), tt.wantModule) {
|
||||
t.Fatalf("ResolvePipeline() error = %v, want %s missing %s capability", err, tt.wantModule, tt.wantCap)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPipelineConfigRejectsMissingTranscriptCapabilityForDNDSpells(t *testing.T) {
|
||||
inputSpec := transcript.ModuleSpec()
|
||||
inputSpec.Provides = withoutCapability(inputSpec.Provides, "source.transcript")
|
||||
chunkSpec := dndSpellsChunkerSpec()
|
||||
chunkSpec.Requires = nil
|
||||
|
||||
_, err := loadDNDSpellsPipelineConfig(t).Resolve(config.ResolveInput{
|
||||
PipelineID: "dnd-spells-fixture",
|
||||
Catalog: dndSpellsTestCatalog(t, dndSpellsCatalogSpecs{
|
||||
input: inputSpec,
|
||||
chunk: chunkSpec,
|
||||
}),
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("Resolve() error = nil, want missing capability error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "missing capability") ||
|
||||
!strings.Contains(err.Error(), "source.transcript") ||
|
||||
!strings.Contains(err.Error(), spells.Key) {
|
||||
t.Fatalf("Resolve() error = %q, want dnd/spells missing source.transcript capability", err.Error())
|
||||
func dndCapabilityProfile() pipeline.PipelineProfile {
|
||||
return pipeline.PipelineProfile{
|
||||
ID: "dnd-capability",
|
||||
Input: pipeline.Binding(transcript.Key),
|
||||
Chunk: pipeline.Binding("fake/chunk"),
|
||||
Artifacts: map[string]pipeline.ArtifactLaneProfile{
|
||||
"spells": {Extract: pipeline.Binding(spells.Key)},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestPipelineConfigRejectsMissingSpellCastsCapabilityForAppendOrder(t *testing.T) {
|
||||
extractorSpec := spells.ModuleSpec()
|
||||
extractorSpec.Provides = withoutCapability(extractorSpec.Provides, "dnd.spell_casts")
|
||||
func dndCapabilityCatalog(t *testing.T, inputSpec, extractorSpec pipeline.ModuleSpec) pipeline.ModuleCatalog {
|
||||
t.Helper()
|
||||
inputs := pipeline.NewInputAdapterRegistry()
|
||||
if err := inputs.RegisterWithSpec(inputSpec, func() (contracts.InputAdapter, error) { return transcript.New(), nil }); err != nil {
|
||||
t.Fatalf("register capability input: %v", err)
|
||||
}
|
||||
|
||||
_, err := loadDNDSpellsPipelineConfig(t).Resolve(config.ResolveInput{
|
||||
PipelineID: "dnd-spells-fixture",
|
||||
Catalog: dndSpellsTestCatalog(t, dndSpellsCatalogSpecs{
|
||||
extractor: extractorSpec,
|
||||
}),
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("Resolve() error = nil, want missing capability error")
|
||||
chunkers := pipeline.NewChunkerRegistry()
|
||||
if err := chunkers.RegisterWithSpec(pipeline.ModuleSpec{Key: "fake/chunk", Stage: pipeline.StageChunk, Provides: []string{"chunks"}}, func() (contracts.Chunker, error) { return dndSpellsChunker{}, nil }); err != nil {
|
||||
t.Fatalf("register capability chunker: %v", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "missing capability") ||
|
||||
!strings.Contains(err.Error(), "dnd.spell_casts") ||
|
||||
!strings.Contains(err.Error(), pipeline.DefaultMergeModule) {
|
||||
t.Fatalf("Resolve() error = %q, want appendorder missing dnd.spell_casts capability", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPipelineConfigRejectsUnknownLaneSelection(t *testing.T) {
|
||||
_, err := loadDNDSpellsPipelineConfig(t).Resolve(config.ResolveInput{
|
||||
PipelineID: "dnd-spells-fixture",
|
||||
Only: []string{"missing"},
|
||||
Catalog: dndSpellsTestCatalog(t, dndSpellsCatalogSpecs{}),
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("Resolve() error = nil, want unknown lane error")
|
||||
extractors := pipeline.NewExtractorRegistry()
|
||||
extractorSpec.ArtifactKind = dnd.SpellListKind
|
||||
if err := pipeline.RegisterExtractor[dnd.SpellList](extractors, extractorSpec, func() (contracts.Extractor[dnd.SpellList], error) {
|
||||
return configExtractor{key: extractorSpec.Key}, nil
|
||||
}); err != nil {
|
||||
t.Fatalf("register capability extractor: %v", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "selected artifact lane") || !strings.Contains(err.Error(), "missing") {
|
||||
t.Fatalf("Resolve() error = %q, want unknown lane context", err.Error())
|
||||
|
||||
codecs := pipeline.NewArtifactCodecRegistry()
|
||||
if err := pipeline.RegisterArtifactCodec(codecs, spellcodec.New()); err != nil {
|
||||
t.Fatalf("register capability codec: %v", err)
|
||||
}
|
||||
|
||||
mergers := pipeline.NewMergerRegistry()
|
||||
if err := pipeline.RegisterMerger[dnd.SpellList](mergers, pipeline.ModuleSpec{
|
||||
Key: pipeline.DefaultMergeModule, Stage: pipeline.StageMerge, ArtifactKind: dnd.SpellListKind, Requires: []string{"dnd.spell_casts"},
|
||||
}, func() (contracts.Merger[dnd.SpellList], error) { return appendorder.NewTyped(appendSpellLists) }); err != nil {
|
||||
t.Fatalf("register capability merger: %v", err)
|
||||
}
|
||||
|
||||
normalizers := pipeline.NewNormalizerRegistry()
|
||||
if err := pipeline.RegisterNormalizer[dnd.SpellList](normalizers, pipeline.ModuleSpec{Key: pipeline.DefaultNormalizeModule, Stage: pipeline.StageNormalize, ArtifactKind: dnd.SpellListKind}, func() (contracts.Normalizer[dnd.SpellList], error) {
|
||||
return noop.NewTyped[dnd.SpellList](), nil
|
||||
}); err != nil {
|
||||
t.Fatalf("register capability normalizer: %v", err)
|
||||
}
|
||||
|
||||
outputs := pipeline.NewOutputEncoderRegistry()
|
||||
if err := outputs.RegisterWithSpec(pipeline.ModuleSpec{Key: pipeline.DefaultOutputModule, Stage: pipeline.StageOutput}, func() (contracts.OutputEncoder, error) { return dndSpellsOutput{}, nil }); err != nil {
|
||||
t.Fatalf("register capability output: %v", err)
|
||||
}
|
||||
|
||||
return pipeline.ModuleCatalog{
|
||||
Inputs: inputs, Chunkers: chunkers, ArtifactCodecs: codecs, Extractors: extractors,
|
||||
Mergers: mergers, Normalizers: normalizers, ValidatorChains: pipeline.NewValidatorChainRegistry(), Outputs: outputs,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user