Add assembled pipeline configuration regression coverage
This commit is contained in:
@@ -1185,7 +1185,7 @@ describe the completed feature once, at the correct canonical owners.
|
|||||||
|
|
||||||
## Stage 22 — Assembled Workflow Regression And Final Validation
|
## Stage 22 — Assembled Workflow Regression And Final Validation
|
||||||
|
|
||||||
**Status: Pending**
|
**Status: Completed**
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,11 @@ package app
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -271,6 +274,188 @@ func TestAssembledLegacyAnalyzeTransitionPublishesOnlyCurrentRecords(t *testing.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAssembledSplitBundleCommandsUseOneEffectiveFamilyConfiguration(t *testing.T) {
|
||||||
|
pipelinePath, campaignPath, sessionPath := assembledSplitBundlePaths()
|
||||||
|
workspacePath := filepath.Join(filepath.Dir(pipelinePath), "workspace")
|
||||||
|
if _, err := os.Stat(workspacePath); !os.IsNotExist(err) {
|
||||||
|
t.Fatalf("example workspace stat = %v, want absent", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var validated bytes.Buffer
|
||||||
|
if err := ConfigValidate(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath}, &validated); err != nil {
|
||||||
|
t.Fatalf("validate production default: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(validated.String(), "profile=production") {
|
||||||
|
t.Fatalf("validate output = %q, want production profile", validated.String())
|
||||||
|
}
|
||||||
|
for _, command := range []func(context.Context, []string, io.Writer) error{ConfigShow, ConfigSources} {
|
||||||
|
if err := command(context.Background(), []string{
|
||||||
|
"--config", pipelinePath, "--campaign-file", campaignPath, "--profile", "testing",
|
||||||
|
}, io.Discard); err != nil {
|
||||||
|
t.Fatalf("testing inspection command %T: %v", command, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var diff bytes.Buffer
|
||||||
|
if err := ConfigDiff(context.Background(), []string{
|
||||||
|
"production", "testing", "--config", pipelinePath, "--campaign-file", campaignPath,
|
||||||
|
}, &diff); err != nil {
|
||||||
|
t.Fatalf("compare profiles: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(diff.String(), "audita.model") || !strings.Contains(diff.String(), "character_items_arannis.profile_id") {
|
||||||
|
t.Fatalf("profile diff = %q, want model and expanded family changes", diff.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
common := []string{
|
||||||
|
"2026-05-03", "--config", pipelinePath, "--campaign-file", campaignPath,
|
||||||
|
"--session", sessionPath, "--profile", "testing",
|
||||||
|
}
|
||||||
|
var planned bytes.Buffer
|
||||||
|
if err := Plan(context.Background(), common, &planned); err != nil {
|
||||||
|
t.Fatalf("plan testing bundle: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(planned.String(), "profile=testing") {
|
||||||
|
t.Fatalf("plan output = %q, want testing provenance", planned.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
original := executeStagesFn
|
||||||
|
t.Cleanup(func() { executeStagesFn = original })
|
||||||
|
var capturedCfg *config.Config
|
||||||
|
var capturedPlan BoundedPlan
|
||||||
|
var capturedOptions RunOptions
|
||||||
|
executeStagesFn = func(_ context.Context, cfg *config.Config, plan BoundedPlan, options RunOptions) (*RunSummary, error) {
|
||||||
|
capturedCfg = cfg
|
||||||
|
capturedPlan = plan
|
||||||
|
capturedOptions = options
|
||||||
|
return &RunSummary{SessionID: cfg.Session.SessionID, ManifestPath: manifestPathForConfig(cfg.Pipeline.Workspace.Root)}, nil
|
||||||
|
}
|
||||||
|
runArgs := append(append([]string(nil), common...), "--from", "analyze", "--through", "analyze", "--artifacts", "character_items_arannis")
|
||||||
|
var runOut bytes.Buffer
|
||||||
|
if err := Run(context.Background(), runArgs, &runOut); err != nil {
|
||||||
|
t.Fatalf("bounded family run: %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(capturedPlan.Names(), []string{"analyze"}) {
|
||||||
|
t.Fatalf("bounded plan = %#v, want analyze only", capturedPlan.Names())
|
||||||
|
}
|
||||||
|
if profile, ok := config.SelectedPipelineProfile(capturedCfg.Pipeline); !ok || profile.Name != "testing" {
|
||||||
|
t.Fatalf("captured profile = %#v, selected=%t", profile, ok)
|
||||||
|
}
|
||||||
|
if digest := config.EffectivePipelineDigest(capturedCfg.Pipeline); digest == "" || !strings.Contains(runOut.String(), "digest="+digest) {
|
||||||
|
t.Fatalf("run output = %q, want effective digest %q", runOut.String(), digest)
|
||||||
|
}
|
||||||
|
if got := capturedOptions.EffectiveArtifacts.Keys(); !reflect.DeepEqual(got, []string{"character_items_arannis"}) {
|
||||||
|
t.Fatalf("effective artifact keys = %#v", got)
|
||||||
|
}
|
||||||
|
if origin, ok := capturedOptions.EffectiveArtifacts.Origin("character_items_arannis"); !ok || origin.Family != "character_items" || origin.CharacterID != "arannis" {
|
||||||
|
t.Fatalf("family origin = %#v, present=%t", origin, ok)
|
||||||
|
}
|
||||||
|
fullFamily, err := resolveEffectiveArtifacts(capturedCfg, []string{"character_items"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("resolve complete family: %v", err)
|
||||||
|
}
|
||||||
|
if got := fullFamily.Keys(); !reflect.DeepEqual(got, []string{"character_items_arannis", "character_items_brenna"}) {
|
||||||
|
t.Fatalf("full family keys = %#v", got)
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(workspacePath); !os.IsNotExist(err) {
|
||||||
|
t.Fatalf("inspection or bounded run created example workspace: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAssembledSplitBundleProfileSwitchRecordsProvenanceAndLimitsReuse(t *testing.T) {
|
||||||
|
production := loadAssembledSplitBundleConfig(t, "")
|
||||||
|
testingCfg := loadAssembledSplitBundleConfig(t, "testing")
|
||||||
|
workspace := t.TempDir()
|
||||||
|
production.Pipeline.Workspace.Root = workspace
|
||||||
|
testingCfg.Pipeline.Workspace.Root = workspace
|
||||||
|
|
||||||
|
names := []string{"prepare", "transcribe", "merge", "polish", "normalize", "trim", "render"}
|
||||||
|
providers := make([]stage.SemanticConfigFingerprinter, len(names))
|
||||||
|
seed := manifest.New(production.Session.SessionID, time.Now().UTC())
|
||||||
|
seed.Campaign = production.Session.Campaign
|
||||||
|
for _, candidate := range stage.All() {
|
||||||
|
seed.MarkStageSucceeded(candidate.Name(), time.Now().UTC(), nil)
|
||||||
|
}
|
||||||
|
for index, name := range names {
|
||||||
|
providers[index] = canonicalSemanticProvider(t, name)
|
||||||
|
fingerprint, err := providers[index].SemanticConfigFingerprint(&stage.Env{Config: production})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("production %s fingerprint: %v", name, err)
|
||||||
|
}
|
||||||
|
seed.Stages[name].SemanticConfig = &fingerprint
|
||||||
|
}
|
||||||
|
store := &manifest.LocalStore{}
|
||||||
|
if err := store.Save(context.Background(), manifestPathForConfig(workspace), seed); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
productionRuns := make([]int, len(names))
|
||||||
|
productionStages := assembledSemanticStages(names, providers, productionRuns)
|
||||||
|
productionSummary, err := executeStages(context.Background(), production, productionStages, RunOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("record production provenance: %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(productionRuns, make([]int, len(names))) {
|
||||||
|
t.Fatalf("production runs = %v, want complete reuse", productionRuns)
|
||||||
|
}
|
||||||
|
assertAssembledProvenance(t, store, productionSummary, "production", config.EffectivePipelineDigest(production.Pipeline))
|
||||||
|
|
||||||
|
testingRuns := make([]int, len(names))
|
||||||
|
testingStages := assembledSemanticStages(names, providers, testingRuns)
|
||||||
|
testingSummary, err := executeStages(context.Background(), testingCfg, testingStages, RunOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("switch to testing profile: %v", err)
|
||||||
|
}
|
||||||
|
if got, want := testingRuns, []int{0, 0, 0, 1, 1, 1, 1}; !reflect.DeepEqual(got, want) {
|
||||||
|
t.Fatalf("testing profile runs = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
assertAssembledProvenance(t, store, testingSummary, "testing", config.EffectivePipelineDigest(testingCfg.Pipeline))
|
||||||
|
}
|
||||||
|
|
||||||
|
func assembledSplitBundlePaths() (pipelinePath, campaignPath, sessionPath string) {
|
||||||
|
examplesDir := filepath.Join("..", "..", "examples")
|
||||||
|
return filepath.Join(examplesDir, "production-testing", "pipeline.yml"),
|
||||||
|
filepath.Join(examplesDir, "campaigns", "sample-campaign", "campaign.yml"),
|
||||||
|
filepath.Join(examplesDir, "session.local-audio.yml")
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadAssembledSplitBundleConfig(t *testing.T, profile string) *config.Config {
|
||||||
|
t.Helper()
|
||||||
|
pipelinePath, campaignPath, sessionPath := assembledSplitBundlePaths()
|
||||||
|
options := config.SessionLoadOptions{}
|
||||||
|
if profile != "" {
|
||||||
|
options.Profile = &profile
|
||||||
|
}
|
||||||
|
cfg, err := config.LoadWithSessionOptions(pipelinePath, campaignPath, sessionPath, options)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("load split bundle profile %q: %v", profile, err)
|
||||||
|
}
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func assembledSemanticStages(names []string, providers []stage.SemanticConfigFingerprinter, runs []int) []stage.Stage {
|
||||||
|
stages := make([]stage.Stage, 0, len(names))
|
||||||
|
for index, name := range names {
|
||||||
|
stages = append(stages, semanticContractRunStub{name: name, provider: providers[index], runs: &runs[index]})
|
||||||
|
}
|
||||||
|
return stages
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertAssembledProvenance(t *testing.T, store *manifest.LocalStore, summary *RunSummary, profile, digest string) {
|
||||||
|
t.Helper()
|
||||||
|
session, err := store.Load(context.Background(), summary.ManifestPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
run, err := store.LoadRun(context.Background(), summary.RunManifestPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, value := range []*manifest.EffectiveConfigProvenance{session.EffectiveConfig, run.EffectiveConfig} {
|
||||||
|
if value == nil || value.SelectedProfile == nil || value.SelectedProfile.Name != profile || value.EffectiveConfigDigest != digest {
|
||||||
|
t.Fatalf("effective configuration provenance = %#v, want profile=%q digest=%q", value, profile, digest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func seedAllStagesSucceeded(t *testing.T, cfg *config.Config) {
|
func seedAllStagesSucceeded(t *testing.T, cfg *config.Config) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
m := manifest.New(cfg.Session.SessionID, time.Now().UTC())
|
m := manifest.New(cfg.Session.SessionID, time.Now().UTC())
|
||||||
|
|||||||
Reference in New Issue
Block a user