184 lines
5.2 KiB
Go
184 lines
5.2 KiB
Go
package artifacts
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
func TestRunManifestOmitsEmptyOptionalFields(t *testing.T) {
|
|
gotJSON, err := json.Marshal(RunManifest{})
|
|
if err != nil {
|
|
t.Fatalf("json.Marshal() error = %v", err)
|
|
}
|
|
|
|
if string(gotJSON) != "{}" {
|
|
t.Fatalf("json.Marshal(RunManifest{}) = %s, want {}", gotJSON)
|
|
}
|
|
}
|
|
|
|
func TestRunManifestIncludesPipelineAndArtifactLaneFields(t *testing.T) {
|
|
manifest := RunManifest{
|
|
PipelineID: "pipeline-1",
|
|
PipelineDigest: "sha256:abc123",
|
|
LLMProfiles: []LLMProfileManifest{
|
|
{ID: "default", Provider: "scriptorium", Model: "model-a"},
|
|
},
|
|
ArtifactLanes: []ArtifactLaneManifest{
|
|
{
|
|
ID: "events",
|
|
Extractor: "event-extractor",
|
|
Merger: "appendorder",
|
|
Normalizer: "noop",
|
|
Metadata: map[string]any{
|
|
"extractor": map[string]any{"prompt_id": "test.prompt"},
|
|
},
|
|
},
|
|
},
|
|
ValidatorChains: []ValidatorChainManifest{
|
|
{
|
|
Stage: "extract",
|
|
LaneID: "events",
|
|
ModuleKey: "event-extractor",
|
|
Validators: []ValidatorManifest{
|
|
{Key: "grounded", ExecutionClass: "deterministic"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
gotJSON, err := json.Marshal(manifest)
|
|
if err != nil {
|
|
t.Fatalf("json.Marshal() error = %v", err)
|
|
}
|
|
|
|
var got map[string]any
|
|
if err := json.Unmarshal(gotJSON, &got); err != nil {
|
|
t.Fatalf("json.Unmarshal() error = %v", err)
|
|
}
|
|
|
|
assertHasKeys(t, got, "pipeline_id", "pipeline_digest", "artifact_lanes", "validator_chains", "llm_profiles")
|
|
|
|
profiles, ok := got["llm_profiles"].([]any)
|
|
if !ok {
|
|
t.Fatalf("llm_profiles = %#v, want array", got["llm_profiles"])
|
|
}
|
|
if len(profiles) != 1 {
|
|
t.Fatalf("len(llm_profiles) = %d, want 1", len(profiles))
|
|
}
|
|
profile, ok := profiles[0].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("llm_profiles[0] = %#v, want object", profiles[0])
|
|
}
|
|
assertHasKeys(t, profile, "id", "provider", "model")
|
|
|
|
lanes, ok := got["artifact_lanes"].([]any)
|
|
if !ok {
|
|
t.Fatalf("artifact_lanes = %#v, want array", got["artifact_lanes"])
|
|
}
|
|
if len(lanes) != 1 {
|
|
t.Fatalf("len(artifact_lanes) = %d, want 1", len(lanes))
|
|
}
|
|
lane, ok := lanes[0].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("artifact_lanes[0] = %#v, want object", lanes[0])
|
|
}
|
|
assertHasKeys(t, lane, "id", "extractor", "merger", "normalizer", "metadata")
|
|
|
|
chains, ok := got["validator_chains"].([]any)
|
|
if !ok {
|
|
t.Fatalf("validator_chains = %#v, want array", got["validator_chains"])
|
|
}
|
|
if len(chains) != 1 {
|
|
t.Fatalf("len(validator_chains) = %d, want 1", len(chains))
|
|
}
|
|
chain, ok := chains[0].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("validator_chains[0] = %#v, want object", chains[0])
|
|
}
|
|
assertHasKeys(t, chain, "stage", "lane_id", "module_key", "validators")
|
|
}
|
|
|
|
func TestRunManifestIncludesReferenceProvenance(t *testing.T) {
|
|
manifest := RunManifest{
|
|
References: []ReferenceProvenance{
|
|
{
|
|
Stage: "extract",
|
|
LaneID: "events",
|
|
SlotName: "roster",
|
|
OriginType: "file",
|
|
OriginURI: "file:///tmp/roster.txt",
|
|
Digest: "sha256:reference",
|
|
MediaType: "text/plain; charset=utf-8",
|
|
SizeBytes: 12,
|
|
BindingSource: "config",
|
|
},
|
|
},
|
|
}
|
|
|
|
gotJSON, err := json.Marshal(manifest)
|
|
if err != nil {
|
|
t.Fatalf("json.Marshal() error = %v", err)
|
|
}
|
|
|
|
var got RunManifest
|
|
if err := json.Unmarshal(gotJSON, &got); err != nil {
|
|
t.Fatalf("json.Unmarshal() error = %v", err)
|
|
}
|
|
if len(got.References) != 1 {
|
|
t.Fatalf("len(References) = %d, want 1", len(got.References))
|
|
}
|
|
reference := got.References[0]
|
|
if reference.Stage != "extract" || reference.LaneID != "events" || reference.SlotName != "roster" || reference.OriginType != "file" || reference.OriginURI != "file:///tmp/roster.txt" {
|
|
t.Fatalf("reference provenance = %#v, want lane-scoped origin details", reference)
|
|
}
|
|
if reference.Digest != "sha256:reference" || reference.MediaType != "text/plain; charset=utf-8" || reference.SizeBytes != 12 || reference.BindingSource != "config" {
|
|
t.Fatalf("reference provenance = %#v, want digest/media/size/source details", reference)
|
|
}
|
|
}
|
|
|
|
func TestRunManifestIncludesTopLevelModuleMetadata(t *testing.T) {
|
|
manifest := RunManifest{
|
|
ModuleMetadata: map[string]map[string]any{
|
|
"chunker": {
|
|
"prompt_id": "dnd.scenes",
|
|
"prompt_version": "v1",
|
|
"prompt_sha256": "sha256:abc123",
|
|
"response_schema_key": "dnd_scenes",
|
|
"response_schema_name": "dnd_scenes",
|
|
},
|
|
},
|
|
}
|
|
|
|
gotJSON, err := json.Marshal(manifest)
|
|
if err != nil {
|
|
t.Fatalf("json.Marshal() error = %v", err)
|
|
}
|
|
|
|
var got map[string]any
|
|
if err := json.Unmarshal(gotJSON, &got); err != nil {
|
|
t.Fatalf("json.Unmarshal() error = %v", err)
|
|
}
|
|
|
|
moduleMetadata, ok := got["module_metadata"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("module_metadata = %#v, want object", got["module_metadata"])
|
|
}
|
|
assertHasKeys(t, moduleMetadata, "chunker")
|
|
|
|
chunkerMetadata, ok := moduleMetadata["chunker"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("module_metadata.chunker = %#v, want object", moduleMetadata["chunker"])
|
|
}
|
|
assertHasKeys(t, chunkerMetadata, "prompt_id", "prompt_version", "prompt_sha256", "response_schema_key", "response_schema_name")
|
|
}
|
|
|
|
func assertHasKeys(t *testing.T, values map[string]any, keys ...string) {
|
|
t.Helper()
|
|
|
|
for _, key := range keys {
|
|
if _, ok := values[key]; !ok {
|
|
t.Fatalf("missing key %q in %#v", key, values)
|
|
}
|
|
}
|
|
}
|