Verify WhisperX transport replay
This commit is contained in:
@@ -7,9 +7,12 @@ import (
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/adapters/whisperx"
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/config"
|
||||
@@ -118,6 +121,86 @@ func TestExecuteStagesDefaultWiringWhisperXFailureMarksManifestFailed(t *testing
|
||||
}
|
||||
}
|
||||
|
||||
func TestExhaustedWhisperXFailurePreservesEarlierSpeakerCheckpoint(t *testing.T) {
|
||||
var successful atomic.Bool
|
||||
var requestMu sync.Mutex
|
||||
var requested []string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
file, header, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
t.Errorf("FormFile(file) error = %v", err)
|
||||
http.Error(w, "invalid multipart", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
_, readErr := io.Copy(io.Discard, file)
|
||||
_ = file.Close()
|
||||
if readErr != nil {
|
||||
t.Errorf("read uploaded file: %v", readErr)
|
||||
return
|
||||
}
|
||||
speaker := strings.TrimSuffix(header.Filename, filepath.Ext(header.Filename))
|
||||
requestMu.Lock()
|
||||
requested = append(requested, speaker)
|
||||
requestMu.Unlock()
|
||||
if speaker == "b" && !successful.Load() {
|
||||
http.Error(w, "temporary", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_, _ = w.Write([]byte(`{"segments":[]}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
cfg, store := setupTranscribeRecoveryFixture(t, []string{"a", "b", "c"})
|
||||
setWhisperXConfig(cfg, srv.URL, 1)
|
||||
concurrency := 1
|
||||
cfg.Pipeline.WhisperX.Concurrency = &concurrency
|
||||
httpClient, err := whisperx.NewHTTPClient(whisperx.HTTPClientConfig{
|
||||
TranscribeURL: srv.URL,
|
||||
Language: "en",
|
||||
Timeout: 2 * time.Second,
|
||||
Retries: 1,
|
||||
RetryDelay: time.Millisecond,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("NewHTTPClient() error = %v", err)
|
||||
}
|
||||
transcribe := mustSelectStage(t, "transcribe")
|
||||
|
||||
if _, err := executeStages(context.Background(), cfg, []stage.Stage{transcribe}, RunOptions{
|
||||
Env: &Env{ManifestStore: store, WhisperX: httpClient},
|
||||
}); err == nil {
|
||||
t.Fatal("executeStages() error = nil, want exhausted HTTP failure")
|
||||
}
|
||||
failed := loadTranscribeRecoveryManifest(t, store, cfg)
|
||||
if got := transcribeSpeakerKeys(failed); !slices.Equal(got, []string{"a"}) {
|
||||
t.Fatalf("checkpointed speakers = %#v, want a", got)
|
||||
}
|
||||
requestMu.Lock()
|
||||
firstRequests := append([]string(nil), requested...)
|
||||
requested = nil
|
||||
requestMu.Unlock()
|
||||
if !slices.Equal(firstRequests, []string{"a", "b", "b"}) {
|
||||
t.Fatalf("initial HTTP speakers = %#v, want a then two attempts for b", firstRequests)
|
||||
}
|
||||
|
||||
successful.Store(true)
|
||||
if _, err := executeStages(context.Background(), cfg, []stage.Stage{transcribe}, RunOptions{
|
||||
Env: &Env{ManifestStore: store, WhisperX: httpClient},
|
||||
}); err != nil {
|
||||
t.Fatalf("retry executeStages() error = %v", err)
|
||||
}
|
||||
requestMu.Lock()
|
||||
retryRequests := append([]string(nil), requested...)
|
||||
requestMu.Unlock()
|
||||
if !slices.Equal(retryRequests, []string{"b", "c"}) {
|
||||
t.Fatalf("retry HTTP speakers = %#v, want only b and c", retryRequests)
|
||||
}
|
||||
completed := loadTranscribeRecoveryManifest(t, store, cfg)
|
||||
if got := transcribeSpeakerKeys(completed); !slices.Equal(got, []string{"a", "b", "c"}) {
|
||||
t.Fatalf("completed speakers = %#v, want all speakers", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteStagesExplicitWhisperXInjectionOverridesDefaultWiring(t *testing.T) {
|
||||
cfg := testConfig(t)
|
||||
setWhisperXConfig(cfg, "https://127.0.0.1:1/transcribe", 0)
|
||||
|
||||
Reference in New Issue
Block a user