Add effective artifact catalog command
This commit is contained in:
182
internal/app/config_artifacts_test.go
Normal file
182
internal/app/config_artifacts_test.go
Normal file
@@ -0,0 +1,182 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const artifactCatalogHeader = "key\tsource\tdefinitions\tenabled\toutput\tdependencies\tfamily\tcharacter\tfamily_source\tparty_source\n"
|
||||
|
||||
func TestConfigArtifactsReportsOrdinaryCatalogWithoutCampaign(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
pipelinePath := filepath.Join(dir, "pipeline.yml")
|
||||
mustWriteTestFile(t, pipelinePath, `workspace:
|
||||
root: `+filepath.Join(dir, "workspace")+`
|
||||
whisperx:
|
||||
transcribe_url: https://transcription.example.com/transcribe
|
||||
scriptorium:
|
||||
binary: scriptorium
|
||||
artifacts:
|
||||
zeta:
|
||||
enabled: false
|
||||
output_path: artifacts/zeta.md
|
||||
alpha:
|
||||
enabled: false
|
||||
output_path: artifacts/alpha.md
|
||||
inputs:
|
||||
upstream: {source: narratio.artifact.zeta, required: true}
|
||||
`)
|
||||
|
||||
var out bytes.Buffer
|
||||
if err := ConfigArtifacts(context.Background(), []string{"--config", pipelinePath}, &out); err != nil {
|
||||
t.Fatalf("ConfigArtifacts() error = %v", err)
|
||||
}
|
||||
lines := strings.Split(strings.TrimSuffix(out.String(), "\n"), "\n")
|
||||
if len(lines) != 3 || !strings.HasPrefix(lines[1], "alpha\t") || !strings.HasPrefix(lines[2], "zeta\t") {
|
||||
t.Fatalf("catalog order/output = %q", out.String())
|
||||
}
|
||||
alpha := strings.Split(lines[1], "\t")
|
||||
if len(alpha) != 10 {
|
||||
t.Fatalf("alpha fields = %#v", alpha)
|
||||
}
|
||||
if alpha[1] != "narratio.artifact.alpha" || alpha[2] != pipelinePath || alpha[3] != "false" || alpha[4] != "artifacts/alpha.md" || alpha[5] != "zeta" {
|
||||
t.Fatalf("alpha record = %#v", alpha)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigArtifactsEmptyCatalogWritesOnlyHeader(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
pipelinePath := filepath.Join(dir, "pipeline.yml")
|
||||
mustWriteTestFile(t, pipelinePath, "workspace:\n root: "+filepath.Join(dir, "workspace")+"\nwhisperx:\n transcribe_url: https://transcription.example.com/transcribe\n")
|
||||
var out bytes.Buffer
|
||||
if err := ConfigArtifacts(context.Background(), []string{"--config", pipelinePath}, &out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if out.String() != artifactCatalogHeader {
|
||||
t.Fatalf("empty catalog = %q, want header only", out.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigArtifactsReportsGeneratedFamilyProvenance(t *testing.T) {
|
||||
pipelinePath, campaignPath := writeInspectionFamilyConfig(t)
|
||||
var out bytes.Buffer
|
||||
if err := ConfigArtifacts(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath}, &out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
records := catalogRecordsByKey(t, out.String())
|
||||
meta := records["character_meta_arannis"]
|
||||
note := records["character_note_arannis"]
|
||||
partyPath := filepath.Join(filepath.Dir(campaignPath), "party.yml")
|
||||
if len(meta) != 10 || meta[6] != "character_meta" || meta[7] != "arannis" || meta[8] != pipelinePath || meta[9] != partyPath {
|
||||
t.Fatalf("generated meta record = %#v", meta)
|
||||
}
|
||||
if len(note) != 10 || note[5] != "character_meta_arannis" || note[6] != "character_note" {
|
||||
t.Fatalf("generated note record = %#v", note)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigArtifactsReportsBaseAndProfileContributors(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
pipelinePath := filepath.Join(dir, "pipeline.yml")
|
||||
profilePath := filepath.Join(dir, "profiles", "testing.yml")
|
||||
mustWriteTestFile(t, pipelinePath, `workspace:
|
||||
root: /srv/narratio
|
||||
whisperx:
|
||||
transcribe_url: https://transcription.example.com/transcribe
|
||||
scriptorium:
|
||||
binary: scriptorium
|
||||
artifacts:
|
||||
notes:
|
||||
enabled: false
|
||||
output_path: artifacts/notes.md
|
||||
`)
|
||||
mustWriteTestFile(t, profilePath, `scriptorium:
|
||||
artifacts:
|
||||
notes:
|
||||
enabled: true
|
||||
prompt_id: notes
|
||||
profile_only:
|
||||
enabled: false
|
||||
output_path: artifacts/profile-only.md
|
||||
`)
|
||||
|
||||
var out bytes.Buffer
|
||||
if err := ConfigArtifacts(context.Background(), []string{"--config", pipelinePath, "--profile", "testing"}, &out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
records := catalogRecordsByKey(t, out.String())
|
||||
if got := strings.Split(records["notes"][2], ","); !reflect.DeepEqual(got, []string{pipelinePath, profilePath}) {
|
||||
t.Fatalf("notes definitions = %#v", got)
|
||||
}
|
||||
if got := records["profile_only"][2]; got != profilePath {
|
||||
t.Fatalf("profile-only definition = %q, want %q", got, profilePath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigArtifactsIdentityDoesNotDependOnDefinitionFilename(t *testing.T) {
|
||||
inlineDir := t.TempDir()
|
||||
inlinePath := filepath.Join(inlineDir, "pipeline.yml")
|
||||
mustWriteTestFile(t, inlinePath, artifactIdentityPipeline("", "recap"))
|
||||
importDir := t.TempDir()
|
||||
importPath := filepath.Join(importDir, "pipeline.yml")
|
||||
mustWriteTestFile(t, importPath, artifactIdentityPipeline("artifacts.yml", ""))
|
||||
mustWriteTestFile(t, filepath.Join(importDir, "artifacts.yml"), "scriptorium:\n artifacts:\n recap:\n enabled: false\n output_path: artifacts/recap.md\n")
|
||||
|
||||
for _, path := range []string{inlinePath, importPath} {
|
||||
var out bytes.Buffer
|
||||
if err := ConfigArtifacts(context.Background(), []string{"--config", path}, &out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := catalogRecordsByKey(t, out.String())["recap"][1]; got != "narratio.artifact.recap" {
|
||||
t.Fatalf("source identity for %s = %q", path, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigArtifactsPropagatesWriterErrorsAndEscapesFields(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
pipelinePath := filepath.Join(dir, "pipeline.yml")
|
||||
mustWriteTestFile(t, pipelinePath, "workspace:\n root: /srv/narratio\nwhisperx:\n transcribe_url: https://transcription.example.com/transcribe\n")
|
||||
want := errors.New("write rejected")
|
||||
err := ConfigArtifacts(context.Background(), []string{"--config", pipelinePath}, rejectingCatalogWriter{err: want})
|
||||
if !errors.Is(err, want) {
|
||||
t.Fatalf("ConfigArtifacts() error = %v, want writer error", err)
|
||||
}
|
||||
if got := escapeCatalogField("a\\b\tc\nd\r"); got != `a\\b\tc\nd\r` {
|
||||
t.Fatalf("escaped field = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func catalogRecordsByKey(t *testing.T, output string) map[string][]string {
|
||||
t.Helper()
|
||||
lines := strings.Split(strings.TrimSuffix(output, "\n"), "\n")
|
||||
if len(lines) == 0 || lines[0]+"\n" != artifactCatalogHeader {
|
||||
t.Fatalf("catalog header = %q", output)
|
||||
}
|
||||
records := make(map[string][]string, len(lines)-1)
|
||||
for _, line := range lines[1:] {
|
||||
fields := strings.Split(line, "\t")
|
||||
records[fields[0]] = fields
|
||||
}
|
||||
return records
|
||||
}
|
||||
|
||||
func artifactIdentityPipeline(importPath, inlineKey string) string {
|
||||
document := "workspace:\n root: /srv/narratio\nwhisperx:\n transcribe_url: https://transcription.example.com/transcribe\nscriptorium:\n binary: scriptorium\n"
|
||||
if importPath != "" {
|
||||
document = "configkit:\n imports:\n - path: " + importPath + "\n" + document
|
||||
}
|
||||
if inlineKey != "" {
|
||||
document += " artifacts:\n " + inlineKey + ":\n enabled: false\n output_path: artifacts/recap.md\n"
|
||||
}
|
||||
return document
|
||||
}
|
||||
|
||||
type rejectingCatalogWriter struct{ err error }
|
||||
|
||||
func (w rejectingCatalogWriter) Write([]byte) (int, error) { return 0, w.err }
|
||||
Reference in New Issue
Block a user