Make typed module spec lookup artifact-aware
This commit is contained in:
@@ -1268,6 +1268,111 @@ func TestRunPipelineReferenceFlagBindsUnambiguousSlot(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCLIReferenceDiscoveryUsesLaneArtifactVariant(t *testing.T) {
|
||||
catalog := referenceVariantCatalog(t)
|
||||
cfg := config.Config{Pipelines: map[string]pipeline.PipelineProfile{
|
||||
"variants": {
|
||||
ID: "variants",
|
||||
Chunk: pipeline.Binding("generic"),
|
||||
Artifacts: map[string]pipeline.ArtifactLaneProfile{
|
||||
"alpha": {
|
||||
Extract: pipeline.Binding("extract/alpha"),
|
||||
Merge: pipeline.Binding("shared/merge"),
|
||||
Normalize: pipeline.Binding("shared/normalize"),
|
||||
},
|
||||
"beta": {
|
||||
Extract: pipeline.Binding("extract/beta"),
|
||||
Merge: pipeline.Binding("shared/merge"),
|
||||
Normalize: pipeline.Binding("shared/normalize"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
targets, err := selectedReferenceTargets(cfg, "variants", nil, catalog)
|
||||
if err != nil {
|
||||
t.Fatalf("selectedReferenceTargets() error = %v, want nil", err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
selector cliReferenceSelector
|
||||
laneID string
|
||||
stage pipeline.ModuleStage
|
||||
}{
|
||||
{
|
||||
name: "qualified merger",
|
||||
selector: cliReferenceSelector{LaneID: "alpha", Stage: pipeline.StageMerge, SlotName: "alpha_merge"},
|
||||
laneID: "alpha",
|
||||
stage: pipeline.StageMerge,
|
||||
},
|
||||
{
|
||||
name: "unqualified merger",
|
||||
selector: cliReferenceSelector{Stage: pipeline.StageMerge, SlotName: "beta_merge"},
|
||||
laneID: "beta",
|
||||
stage: pipeline.StageMerge,
|
||||
},
|
||||
{
|
||||
name: "flat normalizer",
|
||||
selector: cliReferenceSelector{SlotName: "alpha_normalize"},
|
||||
laneID: "alpha",
|
||||
stage: pipeline.StageNormalize,
|
||||
},
|
||||
{
|
||||
name: "lane normalizer",
|
||||
selector: cliReferenceSelector{LaneID: "beta", SlotName: "beta_normalize"},
|
||||
laneID: "beta",
|
||||
stage: pipeline.StageNormalize,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
target, err := resolveCLIReferenceTarget(targets, tc.selector)
|
||||
if err != nil {
|
||||
t.Fatalf("resolveCLIReferenceTarget() error = %v, want nil", err)
|
||||
}
|
||||
if target.laneID != tc.laneID || target.stage != tc.stage {
|
||||
t.Fatalf("target = %#v, want lane %q stage %q", target, tc.laneID, tc.stage)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
_, err = resolveCLIReferenceTarget(targets, cliReferenceSelector{LaneID: "beta", Stage: pipeline.StageMerge, SlotName: "alpha_merge"})
|
||||
if err == nil || !strings.Contains(err.Error(), "not declared") {
|
||||
t.Fatalf("beta alpha-variant reference error = %v, want slot rejection", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCLIReferenceDiscoveryReportsMissingArtifactVariant(t *testing.T) {
|
||||
catalog := referenceVariantCatalog(t)
|
||||
if err := pipeline.RegisterExtractor(catalog.Extractors, pipeline.ModuleSpec{Key: "extract/missing", Stage: pipeline.StageExtract, ArtifactKind: "test/missing"}, func() (contracts.Extractor[fakeRunArtifact], error) {
|
||||
return referenceVariantExtractor{key: "extract/missing"}, nil
|
||||
}); err != nil {
|
||||
t.Fatalf("register missing-kind extractor: %v", err)
|
||||
}
|
||||
cfg := config.Config{Pipelines: map[string]pipeline.PipelineProfile{
|
||||
"variants": {
|
||||
ID: "variants",
|
||||
Artifacts: map[string]pipeline.ArtifactLaneProfile{
|
||||
"missing": {
|
||||
Extract: pipeline.Binding("extract/missing"),
|
||||
Merge: pipeline.Binding("shared/merge"),
|
||||
Normalize: pipeline.Binding("shared/normalize"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
_, err := selectedReferenceTargets(cfg, "variants", nil, catalog)
|
||||
want := []string{"pipeline \"variants\"", "lane \"missing\"", "merge module \"shared/merge\"", "artifact kind \"test/missing\"", "registered kinds: test/alpha, test/beta"}
|
||||
if err == nil {
|
||||
t.Fatal("selectedReferenceTargets() error = nil, want missing variant error")
|
||||
}
|
||||
for _, value := range want {
|
||||
if !strings.Contains(err.Error(), value) {
|
||||
t.Fatalf("selectedReferenceTargets() error = %q, want %q", err, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunPipelineReferenceFlagBindsLaneQualifiedSlot(t *testing.T) {
|
||||
configPath := writeTestConfig(t, testConfigYAML("example", "events", "notes"))
|
||||
inputPath := filepath.Join(t.TempDir(), "missing.json")
|
||||
@@ -3652,6 +3757,30 @@ const fakeRunArtifactKind contracts.ArtifactKind = "test/fake"
|
||||
type fakeRunArtifact struct {
|
||||
Value bool `json:"value"`
|
||||
}
|
||||
|
||||
type referenceVariantExtractor struct{ key string }
|
||||
|
||||
func (e referenceVariantExtractor) Key() string { return e.key }
|
||||
func (referenceVariantExtractor) ReferenceSlots() []contracts.ReferenceSlot { return nil }
|
||||
func (referenceVariantExtractor) Extract(context.Context, contracts.TypedExtractionRequest) (contracts.TypedExtractionResult[fakeRunArtifact], error) {
|
||||
return contracts.TypedExtractionResult[fakeRunArtifact]{}, nil
|
||||
}
|
||||
|
||||
type referenceVariantMerger struct{ key string }
|
||||
|
||||
func (m referenceVariantMerger) Key() string { return m.key }
|
||||
func (referenceVariantMerger) Merge(context.Context, contracts.TypedMergeRequest[fakeRunArtifact]) (contracts.TypedMergeResult[fakeRunArtifact], error) {
|
||||
return contracts.TypedMergeResult[fakeRunArtifact]{}, nil
|
||||
}
|
||||
|
||||
type referenceVariantNormalizer struct{ key string }
|
||||
|
||||
func (n referenceVariantNormalizer) Key() string { return n.key }
|
||||
func (referenceVariantNormalizer) ReferenceSlots() []contracts.ReferenceSlot { return nil }
|
||||
func (referenceVariantNormalizer) Normalize(context.Context, contracts.TypedNormalizeRequest[fakeRunArtifact]) (contracts.TypedNormalizeResult[fakeRunArtifact], error) {
|
||||
return contracts.TypedNormalizeResult[fakeRunArtifact]{}, nil
|
||||
}
|
||||
|
||||
type fakeRunCodec struct{}
|
||||
|
||||
func (fakeRunCodec) Kind() contracts.ArtifactKind { return fakeRunArtifactKind }
|
||||
@@ -3994,6 +4123,52 @@ func fakeCatalog(t *testing.T, overrides ...pipeline.ModuleSpec) pipeline.Module
|
||||
}
|
||||
}
|
||||
|
||||
func referenceVariantCatalog(t *testing.T) pipeline.ModuleCatalog {
|
||||
t.Helper()
|
||||
chunkers := pipeline.NewChunkerRegistry()
|
||||
extractors := pipeline.NewExtractorRegistry()
|
||||
mergers := pipeline.NewMergerRegistry()
|
||||
normalizers := pipeline.NewNormalizerRegistry()
|
||||
mustRegisterChunker(t, chunkers, pipeline.ModuleSpec{Key: "generic", Stage: pipeline.StageChunk})
|
||||
|
||||
for _, item := range []struct {
|
||||
key string
|
||||
kind contracts.ArtifactKind
|
||||
}{
|
||||
{key: "extract/alpha", kind: "test/alpha"},
|
||||
{key: "extract/beta", kind: "test/beta"},
|
||||
} {
|
||||
item := item
|
||||
if err := pipeline.RegisterExtractor(extractors, pipeline.ModuleSpec{Key: item.key, Stage: pipeline.StageExtract, ArtifactKind: item.kind}, func() (contracts.Extractor[fakeRunArtifact], error) {
|
||||
return referenceVariantExtractor{key: item.key}, nil
|
||||
}); err != nil {
|
||||
t.Fatalf("register extractor %q: %v", item.key, err)
|
||||
}
|
||||
}
|
||||
for _, item := range []struct {
|
||||
kind contracts.ArtifactKind
|
||||
mergeSlot string
|
||||
normalizeSlot string
|
||||
}{
|
||||
{kind: "test/beta", mergeSlot: "beta_merge", normalizeSlot: "beta_normalize"},
|
||||
{kind: "test/alpha", mergeSlot: "alpha_merge", normalizeSlot: "alpha_normalize"},
|
||||
} {
|
||||
mergeSpec := pipeline.ModuleSpec{Key: "shared/merge", Stage: pipeline.StageMerge, ArtifactKind: item.kind, ReferenceSlots: []contracts.ReferenceSlot{{Name: item.mergeSlot}}}
|
||||
if err := pipeline.RegisterMerger(mergers, mergeSpec, func() (contracts.Merger[fakeRunArtifact], error) {
|
||||
return referenceVariantMerger{key: "shared/merge"}, nil
|
||||
}); err != nil {
|
||||
t.Fatalf("register merger %q: %v", item.kind, err)
|
||||
}
|
||||
normalizeSpec := pipeline.ModuleSpec{Key: "shared/normalize", Stage: pipeline.StageNormalize, ArtifactKind: item.kind, ReferenceSlots: []contracts.ReferenceSlot{{Name: item.normalizeSlot}}}
|
||||
if err := pipeline.RegisterNormalizer(normalizers, normalizeSpec, func() (contracts.Normalizer[fakeRunArtifact], error) {
|
||||
return referenceVariantNormalizer{key: "shared/normalize"}, nil
|
||||
}); err != nil {
|
||||
t.Fatalf("register normalizer %q: %v", item.kind, err)
|
||||
}
|
||||
}
|
||||
return pipeline.ModuleCatalog{Chunkers: chunkers, Extractors: extractors, Mergers: mergers, Normalizers: normalizers}
|
||||
}
|
||||
|
||||
func mustRegisterInput(t *testing.T, registry *pipeline.InputAdapterRegistry, spec pipeline.ModuleSpec) {
|
||||
t.Helper()
|
||||
if err := registry.RegisterWithSpec(spec, func() (contracts.InputAdapter, error) { return fakeRunInputAdapter{}, nil }); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user