149 lines
4.5 KiB
Go
149 lines
4.5 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.maximumdirect.net/eric/narratio/internal/config"
|
|
"gitea.maximumdirect.net/eric/narratio/internal/manifest"
|
|
"gitea.maximumdirect.net/eric/narratio/internal/stage"
|
|
)
|
|
|
|
type failingStage struct {
|
|
name string
|
|
err error
|
|
}
|
|
|
|
func (s failingStage) Name() string { return s.name }
|
|
func (s failingStage) Declares() stage.IODecl { return stage.IODecl{} }
|
|
func (s failingStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) {
|
|
return nil, s.err
|
|
}
|
|
|
|
func TestExecuteStagesPlaceholderSuccessUpdatesManifest(t *testing.T) {
|
|
cfg := testConfig(t)
|
|
|
|
summary, err := executeStages(context.Background(), cfg, BuildFullPlan(), RunOptions{})
|
|
if err != nil {
|
|
t.Fatalf("executeStages() error = %v", err)
|
|
}
|
|
if len(summary.StageNames) != 8 {
|
|
t.Fatalf("stage count = %d, want 8", len(summary.StageNames))
|
|
}
|
|
|
|
store := &manifest.LocalStore{}
|
|
m, err := store.Load(context.Background(), summary.ManifestPath)
|
|
if err != nil {
|
|
t.Fatalf("Load manifest error = %v", err)
|
|
}
|
|
|
|
for _, name := range []string{"prepare", "transcribe", "normalize", "merge", "polish", "analyze", "archive", "notify"} {
|
|
sr := m.Stages[name]
|
|
if sr == nil {
|
|
t.Fatalf("missing stage record %q", name)
|
|
}
|
|
if sr.Status != manifest.StatusSucceeded {
|
|
t.Fatalf("stage %q status = %q, want %q", name, sr.Status, manifest.StatusSucceeded)
|
|
}
|
|
if sr.Metadata == nil || sr.Metadata["placeholder"] != true {
|
|
t.Fatalf("stage %q missing placeholder metadata", name)
|
|
}
|
|
}
|
|
|
|
if _, err := os.Stat(summary.ManifestPath); err != nil {
|
|
t.Fatalf("manifest file missing at %q: %v", summary.ManifestPath, err)
|
|
}
|
|
}
|
|
|
|
func TestExecuteStagesFailureUpdatesManifest(t *testing.T) {
|
|
cfg := testConfig(t)
|
|
|
|
stages := []stage.Stage{
|
|
BuildFullPlan()[0],
|
|
failingStage{name: "transcribe", err: errors.New("boom")},
|
|
BuildFullPlan()[2],
|
|
}
|
|
|
|
summary, err := executeStages(context.Background(), cfg, stages, RunOptions{})
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
if summary != nil {
|
|
t.Fatalf("summary = %#v, want nil on failure", summary)
|
|
}
|
|
if !strings.Contains(err.Error(), "stage \"transcribe\" failed") {
|
|
t.Fatalf("error = %q, want stage failure", err.Error())
|
|
}
|
|
|
|
manifestPath := manifestPathFor(cfg)
|
|
store := &manifest.LocalStore{}
|
|
m, loadErr := store.Load(context.Background(), manifestPath)
|
|
if loadErr != nil {
|
|
t.Fatalf("Load manifest error = %v", loadErr)
|
|
}
|
|
|
|
if got := m.Stages["prepare"]; got == nil || got.Status != manifest.StatusSucceeded {
|
|
t.Fatalf("prepare status = %#v, want succeeded", got)
|
|
}
|
|
if got := m.Stages["transcribe"]; got == nil || got.Status != manifest.StatusFailed {
|
|
t.Fatalf("transcribe status = %#v, want failed", got)
|
|
}
|
|
if got := m.Stages["normalize"]; got != nil {
|
|
t.Fatalf("normalize should not run, got %#v", got)
|
|
}
|
|
}
|
|
|
|
func testConfig(t *testing.T) *config.Config {
|
|
t.Helper()
|
|
|
|
workspace := t.TempDir()
|
|
return &config.Config{
|
|
Pipeline: &config.PipelineConfig{Workspace: config.WorkspaceConfig{Root: workspace}},
|
|
Session: &config.SessionConfig{
|
|
SessionID: "2026-05-03",
|
|
Inputs: config.SessionInputsConfig{
|
|
AudioDir: "./audio",
|
|
SpeakersFile: "./speakers.yml",
|
|
AutocorrectFile: "./autocorrect.yml",
|
|
GlossaryFile: "./glossary.yml",
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func TestExecuteStagesLoadsExistingManifest(t *testing.T) {
|
|
cfg := testConfig(t)
|
|
manifestPath := manifestPathFor(cfg)
|
|
store := &manifest.LocalStore{}
|
|
|
|
existing := manifest.New(cfg.Session.SessionID, time.Date(2026, 5, 3, 1, 0, 0, 0, time.UTC))
|
|
existing.MarkStageSucceeded("prepare", time.Date(2026, 5, 3, 1, 1, 0, 0, time.UTC), nil)
|
|
if err := os.MkdirAll(filepath.Dir(manifestPath), 0o755); err != nil {
|
|
t.Fatalf("MkdirAll() error = %v", err)
|
|
}
|
|
if err := store.Save(context.Background(), manifestPath, existing); err != nil {
|
|
t.Fatalf("Save manifest error = %v", err)
|
|
}
|
|
|
|
_, err := executeStages(context.Background(), cfg, []stage.Stage{BuildFullPlan()[1]}, RunOptions{})
|
|
if err != nil {
|
|
t.Fatalf("executeStages() error = %v", err)
|
|
}
|
|
|
|
loaded, err := store.Load(context.Background(), manifestPath)
|
|
if err != nil {
|
|
t.Fatalf("Load manifest error = %v", err)
|
|
}
|
|
if loaded.Stages["prepare"] == nil || loaded.Stages["prepare"].Status != manifest.StatusSucceeded {
|
|
t.Fatalf("existing stage prepare should remain succeeded")
|
|
}
|
|
if loaded.Stages["transcribe"] == nil || loaded.Stages["transcribe"].Status != manifest.StatusSucceeded {
|
|
t.Fatalf("transcribe should be succeeded after run")
|
|
}
|
|
}
|