Files
Cyrene_v2/internal/runtime/multimodal/voice/service_test.go
T

109 lines
2.4 KiB
Go

package voice
import (
"context"
"errors"
"sync"
"testing"
"time"
)
func TestService_STTAndTTS(t *testing.T) {
t.Parallel()
chain := NewChain(
NewProvider("cloud", &stubSTT{text: "transcribed"}, &stubTTS{audio: Audio{Format: "mp3", Data: []byte("a")}}),
)
svc := NewService(chain)
defer svc.Close()
text, err := svc.STT(context.Background(), Audio{Format: "wav", Data: []byte("x")})
if err != nil {
t.Fatalf("STT error: %v", err)
}
if text != "transcribed" {
t.Errorf("text = %q, want transcribed", text)
}
audio, err := svc.TTS(context.Background(), "hello")
if err != nil {
t.Fatalf("TTS error: %v", err)
}
if string(audio.Data) != "a" || audio.Format != "mp3" {
t.Errorf("audio = %+v, want mp3/a", audio)
}
}
func TestService_CloseStopsNewCalls(t *testing.T) {
t.Parallel()
svc := NewService(NewChain(SilentProvider()))
svc.Close()
_, err := svc.STT(context.Background(), Audio{})
if !errors.Is(err, ErrClosed) {
t.Fatalf("err = %v, want ErrClosed", err)
}
}
// blockingSTT blocks until its context is canceled, marking that it started.
type blockingSTT struct {
started chan struct{}
once sync.Once
}
func (b *blockingSTT) STT(ctx context.Context, _ Audio) (string, error) {
b.once.Do(func() { close(b.started) })
<-ctx.Done()
return "", ctx.Err()
}
func TestService_CloseCancelsInFlightWorker(t *testing.T) {
t.Parallel()
blk := &blockingSTT{started: make(chan struct{})}
chain := NewChain(NewProvider("cloud", blk, nil))
svc := NewService(chain)
done := make(chan struct{})
go func() {
defer close(done)
_, _ = svc.STT(context.Background(), Audio{Format: "wav", Data: []byte("x")})
}()
select {
case <-blk.started:
case <-time.After(2 * time.Second):
t.Fatal("provider never started")
}
svc.Close()
select {
case <-done:
case <-time.After(2 * time.Second):
t.Fatal("STT call did not return after Close; worker likely leaked")
}
}
func TestService_CallerCancelUnblocks(t *testing.T) {
t.Parallel()
blk := &blockingSTT{started: make(chan struct{})}
svc := NewService(NewChain(NewProvider("cloud", blk, nil)))
defer svc.Close()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
done := make(chan struct{})
go func() {
defer close(done)
_, _ = svc.STT(ctx, Audio{Format: "wav", Data: []byte("x")})
}()
<-blk.started
cancel()
select {
case <-done:
case <-time.After(2 * time.Second):
t.Fatal("caller cancellation did not unblock STT")
}
}