173 lines
4.6 KiB
Go
173 lines
4.6 KiB
Go
package app
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.maximumdirect.net/eric/narratio/internal/manifest"
|
|
)
|
|
|
|
func TestExecuteValidCommands(t *testing.T) {
|
|
pipelinePath, sessionPath := writeValidConfigFiles(t)
|
|
manifestPath := writeManifestPathForExecute(t)
|
|
|
|
cases := []struct {
|
|
name string
|
|
args []string
|
|
wantOut string
|
|
}{
|
|
{name: "run", args: []string{"run", "--config", pipelinePath, "--session", sessionPath}, wantOut: "narratio run: configuration loaded and valid"},
|
|
{name: "plan", args: []string{"plan", "--config", pipelinePath, "--session", sessionPath}, wantOut: "narratio plan: configuration loaded and valid"},
|
|
{name: "status", args: []string{"status", "--manifest", manifestPath}, wantOut: "session_id: 2026-05-03"},
|
|
{name: "resume", args: []string{"resume"}, wantOut: "narratio resume: not yet implemented"},
|
|
{name: "run-stage", args: []string{"run-stage", "polish"}, wantOut: "narratio run-stage: not yet implemented"},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var stdout bytes.Buffer
|
|
var stderr bytes.Buffer
|
|
|
|
code := Execute(tc.args, &stdout, &stderr)
|
|
if code != 0 {
|
|
t.Fatalf("exit code = %d, want 0", code)
|
|
}
|
|
if stderr.Len() != 0 {
|
|
t.Fatalf("stderr = %q, want empty", stderr.String())
|
|
}
|
|
if !strings.Contains(stdout.String(), tc.wantOut) {
|
|
t.Fatalf("stdout = %q, want to contain %q", stdout.String(), tc.wantOut)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExecuteMissingRequiredFlags(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
args []string
|
|
want string
|
|
}{
|
|
{name: "run missing flags", args: []string{"run"}, want: "run: --config and --session are required"},
|
|
{name: "plan missing flags", args: []string{"plan"}, want: "plan: --config and --session are required"},
|
|
{name: "status missing flags", args: []string{"status"}, want: "status: --manifest is required"},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var stdout bytes.Buffer
|
|
var stderr bytes.Buffer
|
|
|
|
code := Execute(tc.args, &stdout, &stderr)
|
|
if code == 0 {
|
|
t.Fatalf("exit code = 0, want non-zero")
|
|
}
|
|
if stdout.Len() != 0 {
|
|
t.Fatalf("stdout = %q, want empty", stdout.String())
|
|
}
|
|
if !strings.Contains(stderr.String(), tc.want) {
|
|
t.Fatalf("stderr = %q, want to contain %q", stderr.String(), tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExecuteInvalidCommand(t *testing.T) {
|
|
var stdout bytes.Buffer
|
|
var stderr bytes.Buffer
|
|
|
|
code := Execute([]string{"bogus"}, &stdout, &stderr)
|
|
if code == 0 {
|
|
t.Fatalf("exit code = 0, want non-zero")
|
|
}
|
|
if stdout.Len() != 0 {
|
|
t.Fatalf("stdout = %q, want empty", stdout.String())
|
|
}
|
|
out := stderr.String()
|
|
if !strings.Contains(out, "unknown command") {
|
|
t.Fatalf("stderr = %q, want unknown command message", out)
|
|
}
|
|
if !strings.Contains(out, "Usage: narratio") {
|
|
t.Fatalf("stderr = %q, want usage message", out)
|
|
}
|
|
}
|
|
|
|
func TestExecuteMissingCommand(t *testing.T) {
|
|
var stdout bytes.Buffer
|
|
var stderr bytes.Buffer
|
|
|
|
code := Execute(nil, &stdout, &stderr)
|
|
if code == 0 {
|
|
t.Fatalf("exit code = 0, want non-zero")
|
|
}
|
|
if stdout.Len() != 0 {
|
|
t.Fatalf("stdout = %q, want empty", stdout.String())
|
|
}
|
|
if !strings.Contains(stderr.String(), "Usage: narratio") {
|
|
t.Fatalf("stderr = %q, want usage message", stderr.String())
|
|
}
|
|
}
|
|
|
|
func writeValidConfigFiles(t *testing.T) (string, string) {
|
|
t.Helper()
|
|
|
|
dir := t.TempDir()
|
|
pipelinePath := filepath.Join(dir, "pipeline.yml")
|
|
sessionPath := filepath.Join(dir, "session.yml")
|
|
|
|
pipelineYAML := `workspace:
|
|
root: /tmp/narratio
|
|
storage:
|
|
backend: s3
|
|
whisperx:
|
|
timeout: 15m
|
|
seriatim:
|
|
timeout: 30s
|
|
audita:
|
|
timeout: 1h
|
|
analyzer:
|
|
timeout: 20m
|
|
artifacts:
|
|
output_dir: artifacts
|
|
notification:
|
|
timeout: 10s
|
|
`
|
|
|
|
sessionYAML := `session_id: 2026-05-03
|
|
inputs:
|
|
audio_dir: ./audio
|
|
speakers_file: ./speakers.yml
|
|
autocorrect_file: ./autocorrect.yml
|
|
glossary_file: ./glossary.yml
|
|
`
|
|
|
|
if err := os.WriteFile(pipelinePath, []byte(pipelineYAML), 0o644); err != nil {
|
|
t.Fatalf("write pipeline config: %v", err)
|
|
}
|
|
if err := os.WriteFile(sessionPath, []byte(sessionYAML), 0o644); err != nil {
|
|
t.Fatalf("write session config: %v", err)
|
|
}
|
|
|
|
return pipelinePath, sessionPath
|
|
}
|
|
|
|
func writeManifestPathForExecute(t *testing.T) string {
|
|
t.Helper()
|
|
|
|
store := &manifest.LocalStore{}
|
|
m := manifest.New("2026-05-03", time.Date(2026, 5, 3, 10, 0, 0, 0, time.UTC))
|
|
m.MarkStageSucceeded("prepare", time.Date(2026, 5, 3, 10, 1, 0, 0, time.UTC), nil)
|
|
|
|
path := filepath.Join(t.TempDir(), "manifest.json")
|
|
if err := store.Save(context.Background(), path, m); err != nil {
|
|
t.Fatalf("save manifest: %v", err)
|
|
}
|
|
|
|
return path
|
|
}
|