Define adapter interfaces and fake implementations

This commit is contained in:
2026-05-02 11:16:27 -05:00
parent 78e7e4f41b
commit 2854da48c2
24 changed files with 876 additions and 73 deletions

View File

@@ -9,6 +9,13 @@ import (
"testing"
"time"
"gitea.maximumdirect.net/eric/narratio/internal/adapters/analyzer"
"gitea.maximumdirect.net/eric/narratio/internal/adapters/audita"
"gitea.maximumdirect.net/eric/narratio/internal/adapters/notify"
"gitea.maximumdirect.net/eric/narratio/internal/adapters/seriatim"
"gitea.maximumdirect.net/eric/narratio/internal/adapters/storage"
"gitea.maximumdirect.net/eric/narratio/internal/adapters/whisperx"
"gitea.maximumdirect.net/eric/narratio/internal/artifacts"
"gitea.maximumdirect.net/eric/narratio/internal/config"
"gitea.maximumdirect.net/eric/narratio/internal/manifest"
"gitea.maximumdirect.net/eric/narratio/internal/stage"
@@ -98,24 +105,6 @@ func TestExecuteStagesFailureUpdatesManifest(t *testing.T) {
}
}
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)
@@ -146,3 +135,67 @@ func TestExecuteStagesLoadsExistingManifest(t *testing.T) {
t.Fatalf("transcribe should be succeeded after run")
}
}
func TestAdapterBackedStageFailureMarksManifestFailed(t *testing.T) {
cases := []struct {
name string
env *Env
}{
{name: "transcribe", env: &Env{WhisperX: &whisperx.FakeClient{Err: errors.New("transcribe fail")}}},
{name: "merge", env: &Env{Seriatim: &seriatim.FakeRunner{Err: errors.New("merge fail")}}},
{name: "polish", env: &Env{Audita: &audita.FakeRunner{Err: errors.New("polish fail")}}},
{name: "analyze", env: &Env{Analyzer: &analyzer.FakeRunner{Err: errors.New("analyze fail")}}},
{name: "archive", env: &Env{Storage: &storage.FakeBackend{Err: errors.New("archive fail")}}},
{name: "notify", env: &Env{Notifier: &notify.FakeSender{Err: errors.New("notify fail")}}},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
cfg := testConfig(t)
selected, err := stage.Select(tc.name)
if err != nil {
t.Fatalf("Select() error = %v", err)
}
artifactStore := artifacts.NewLocalStore(cfg.Pipeline.Workspace.Root)
tc.env.Config = cfg
tc.env.ArtifactStore = artifactStore
tc.env.ManifestStore = &manifest.LocalStore{}
_, runErr := executeStages(context.Background(), cfg, []stage.Stage{selected}, RunOptions{Env: tc.env})
if runErr == nil {
t.Fatal("expected error, got nil")
}
m, loadErr := tc.env.ManifestStore.Load(context.Background(), manifestPathFor(cfg))
if loadErr != nil {
t.Fatalf("load manifest error = %v", loadErr)
}
sr := m.Stages[tc.name]
if sr == nil {
t.Fatalf("missing stage record %q", tc.name)
}
if sr.Status != manifest.StatusFailed {
t.Fatalf("status = %q, want %q", sr.Status, manifest.StatusFailed)
}
})
}
}
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",
},
},
}
}