package stt import ( "context" "errors" "io" "net/http" "net/http/httptest" "strconv" "testing" "time" "github.com/kami/maven/internal/audio" ) func TestHTTPTranscriberSendsRawPCM(t *testing.T) { t.Parallel() var gotBody []byte var gotHeader http.Header srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gotBody, _ = io.ReadAll(r.Body) gotHeader = r.Header.Clone() w.Header().Set("Content-Type", "application/json") _, _ = io.WriteString(w, `{"text":"привет","confidence":0.82}`) })) defer srv.Close() a := audio.Audio{Format: audio.PCM16kMono, Bytes: []byte("pcm-bytes")} tr := NewHTTPTranscriber(srv.URL, "s3cret", "ru", 2*time.Second) text, conf, err := tr.Transcribe(context.Background(), a) if err != nil { t.Fatalf("Transcribe: %v", err) } if text != "привет" || conf != 0.82 { t.Fatalf("got %q %v", text, conf) } if string(gotBody) != "pcm-bytes" { t.Fatalf("body should be the PCM itself, got %q", gotBody) } if got := gotHeader.Get("X-Sample-Rate"); got != strconv.Itoa(audio.PCM16kMono.SampleRate) { t.Fatalf("X-Sample-Rate = %q", got) } if got := gotHeader.Get("X-Language"); got != "ru" { t.Fatalf("X-Language = %q", got) } // Audio is the most sensitive thing crossing this seam. if got := gotHeader.Get("Authorization"); got != "Bearer s3cret" { t.Fatalf("Authorization = %q", got) } } func TestHTTPTranscriberOmitsEmptyToken(t *testing.T) { t.Parallel() var auth string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { auth = r.Header.Get("Authorization") _, _ = io.WriteString(w, `{"text":"x"}`) })) defer srv.Close() a := audio.Audio{Format: audio.PCM16kMono, Bytes: []byte("x")} if _, _, err := NewHTTPTranscriber(srv.URL, "", "ru", time.Second).Transcribe(context.Background(), a); err != nil { t.Fatalf("Transcribe: %v", err) } if auth != "" { t.Fatalf("Authorization should be absent, got %q", auth) } } func TestHTTPTranscriberRefusesWrongFormat(t *testing.T) { t.Parallel() a := audio.Audio{Format: audio.Format{SampleRate: 44100, Channels: 2, SampleBits: 16, Encoding: "pcm_s16le"}} _, _, err := NewHTTPTranscriber("http://example.invalid", "", "ru", time.Second).Transcribe(context.Background(), a) if !errors.Is(err, ErrFormat) { t.Fatalf("want ErrFormat, got %v", err) } } func TestHTTPTranscriberErrorsOnBadStatus(t *testing.T) { t.Parallel() srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusUnauthorized) })) defer srv.Close() a := audio.Audio{Format: audio.PCM16kMono, Bytes: []byte("x")} _, _, err := NewHTTPTranscriber(srv.URL, "", "ru", time.Second).Transcribe(context.Background(), a) if err == nil { t.Fatal("a 401 must be an error, so the Pair falls back") } }