Resolve extraction reference bindings from config
This commit is contained in:
@@ -3,6 +3,7 @@ package pipeline
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -125,6 +126,137 @@ func TestResolvePipelineSelectsOnlyRequestedLanes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvePipelineAppliesReferenceBindings(t *testing.T) {
|
||||
profile := multiLaneProfile()
|
||||
profile.References = map[string]string{
|
||||
" roster ": " ./shared-roster.yml ",
|
||||
"unclaimed": "./ignored.yml",
|
||||
}
|
||||
lane := profile.Artifacts["events"]
|
||||
lane.References = map[string]string{
|
||||
"roster": "./lane-roster.yml",
|
||||
" lore ": " ./lore.md ",
|
||||
}
|
||||
profile.Artifacts["events"] = lane
|
||||
|
||||
catalog := newProfileCatalogWithOverride(t, ModuleSpec{
|
||||
Key: "event-extractor",
|
||||
Stage: StageExtract,
|
||||
Requires: []string{"chunk"},
|
||||
Provides: []string{"candidate"},
|
||||
ReferenceSlots: []contracts.ReferenceSlot{
|
||||
{Name: "roster", Required: true},
|
||||
{Name: "lore"},
|
||||
},
|
||||
})
|
||||
resolved, err := ResolvePipeline(profile, ResolveOptions{Only: []string{"events", "summaries"}}, catalog)
|
||||
if err != nil {
|
||||
t.Fatalf("ResolvePipeline() error = %v, want nil", err)
|
||||
}
|
||||
|
||||
events := resolvedLane(t, resolved.ArtifactLanes, "events")
|
||||
want := []ReferenceBinding{
|
||||
{LaneID: "events", SlotName: "lore", Source: "./lore.md", BindingSource: contracts.ReferenceBindingSourceConfig},
|
||||
{LaneID: "events", SlotName: "roster", Source: "./lane-roster.yml", BindingSource: contracts.ReferenceBindingSourceConfig},
|
||||
}
|
||||
if !reflect.DeepEqual(events.References, want) {
|
||||
t.Fatalf("events references = %#v, want %#v", events.References, want)
|
||||
}
|
||||
summaries := resolvedLane(t, resolved.ArtifactLanes, "summaries")
|
||||
if len(summaries.References) != 0 {
|
||||
t.Fatalf("summaries references = %#v, want none", summaries.References)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvePipelineRejectsUndeclaredReferenceSlot(t *testing.T) {
|
||||
profile := baselineProfile()
|
||||
lane := profile.Artifacts["events"]
|
||||
lane.References = map[string]string{"missing": "./missing.yml"}
|
||||
profile.Artifacts["events"] = lane
|
||||
|
||||
_, err := ResolvePipeline(profile, ResolveOptions{}, newProfileCatalog(t))
|
||||
if err == nil {
|
||||
t.Fatal("ResolvePipeline() error = nil, want error")
|
||||
}
|
||||
assertErrorContains(t, err, "events", "missing", "not declared")
|
||||
}
|
||||
|
||||
func TestResolvePipelineRequiresBoundReferenceSlotsForSelectedLanes(t *testing.T) {
|
||||
catalog := newProfileCatalogWithOverride(t, ModuleSpec{
|
||||
Key: "event-extractor",
|
||||
Stage: StageExtract,
|
||||
Requires: []string{"chunk"},
|
||||
Provides: []string{"candidate"},
|
||||
ReferenceSlots: []contracts.ReferenceSlot{
|
||||
{Name: "roster", Required: true},
|
||||
},
|
||||
})
|
||||
|
||||
if _, err := ResolvePipeline(multiLaneProfile(), ResolveOptions{Only: []string{"notes"}}, catalog); err != nil {
|
||||
t.Fatalf("ResolvePipeline(unselected required slot) error = %v, want nil", err)
|
||||
}
|
||||
|
||||
_, err := ResolvePipeline(multiLaneProfile(), ResolveOptions{Only: []string{"events"}}, catalog)
|
||||
if err == nil {
|
||||
t.Fatal("ResolvePipeline(selected required slot) error = nil, want error")
|
||||
}
|
||||
assertErrorContains(t, err, "events", "required", "roster", "not bound")
|
||||
}
|
||||
|
||||
func TestResolvePipelineReferenceUnbindCanLeaveRequiredSlotMissing(t *testing.T) {
|
||||
profile := baselineProfile()
|
||||
profile.References = map[string]string{"roster": "./roster.yml"}
|
||||
catalog := newProfileCatalogWithOverride(t, ModuleSpec{
|
||||
Key: "event-extractor",
|
||||
Stage: StageExtract,
|
||||
Requires: []string{"chunk"},
|
||||
Provides: []string{"candidate"},
|
||||
ReferenceSlots: []contracts.ReferenceSlot{
|
||||
{Name: "roster", Required: true},
|
||||
},
|
||||
})
|
||||
|
||||
_, err := ResolvePipeline(profile, ResolveOptions{
|
||||
ReferenceUnbinds: []ReferenceUnbind{{LaneID: "events", SlotName: "roster"}},
|
||||
}, catalog)
|
||||
if err == nil {
|
||||
t.Fatal("ResolvePipeline() error = nil, want error")
|
||||
}
|
||||
assertErrorContains(t, err, "events", "required", "roster", "not bound")
|
||||
}
|
||||
|
||||
func TestResolvePipelineUsesReferenceSlotsFromSpecWithoutConstructingExtractor(t *testing.T) {
|
||||
profile := baselineProfile()
|
||||
profile.References = map[string]string{"roster": "./roster.yml"}
|
||||
catalog := emptyProfileCatalog()
|
||||
for _, spec := range defaultProfileSpecs() {
|
||||
if spec.Key != "event-extractor" {
|
||||
registerProfileSpecs(t, catalog, spec)
|
||||
}
|
||||
}
|
||||
if err := catalog.Extractors.RegisterWithSpec(ModuleSpec{
|
||||
Key: "event-extractor",
|
||||
Stage: StageExtract,
|
||||
Requires: []string{"chunk"},
|
||||
Provides: []string{"candidate"},
|
||||
ReferenceSlots: []contracts.ReferenceSlot{
|
||||
{Name: "roster", Required: true},
|
||||
},
|
||||
}, func() (contracts.Extractor, error) {
|
||||
return nil, errors.New("constructor should not run")
|
||||
}); err != nil {
|
||||
t.Fatalf("RegisterWithSpec() error = %v, want nil", err)
|
||||
}
|
||||
|
||||
resolved, err := ResolvePipeline(profile, ResolveOptions{}, catalog)
|
||||
if err != nil {
|
||||
t.Fatalf("ResolvePipeline() error = %v, want nil", err)
|
||||
}
|
||||
if got := resolved.ArtifactLanes[0].References[0].Source; got != "./roster.yml" {
|
||||
t.Fatalf("reference source = %q, want ./roster.yml", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvePipelineRejectsUnknownOnlyLane(t *testing.T) {
|
||||
_, err := ResolvePipeline(multiLaneProfile(), ResolveOptions{Only: []string{"missing"}}, newProfileCatalog(t))
|
||||
if err == nil {
|
||||
@@ -463,6 +595,17 @@ func laneIDs(lanes []ResolvedArtifactLane) []string {
|
||||
return ids
|
||||
}
|
||||
|
||||
func resolvedLane(t *testing.T, lanes []ResolvedArtifactLane, laneID string) ResolvedArtifactLane {
|
||||
t.Helper()
|
||||
for _, lane := range lanes {
|
||||
if lane.ID == laneID {
|
||||
return lane
|
||||
}
|
||||
}
|
||||
t.Fatalf("lane %q not found in %#v", laneID, laneIDs(lanes))
|
||||
return ResolvedArtifactLane{}
|
||||
}
|
||||
|
||||
func assertErrorContains(t *testing.T, err error, values ...string) {
|
||||
t.Helper()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user