107 lines
2.9 KiB
Go
107 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestNormalizeTTS(t *testing.T) {
|
|
cfg := agentCfg{TTSModel: "cosyvoice-v3.5-plus", TTSVoice: "clone-id"}
|
|
|
|
got, err := normalizeTTS(nil, cfg)
|
|
if err != nil || got.Voice != "clone-id" || got.Rate != 1 || got.Pitch != 1 || got.Volume != 50 {
|
|
t.Fatalf("defaults: got=%+v err=%v", got, err)
|
|
}
|
|
|
|
bad := ttsCfg{Model: "m", Voice: "v", Rate: 2.1, Pitch: 1, Volume: 50}
|
|
if _, err := normalizeTTS(&bad, cfg); err == nil {
|
|
t.Fatal("expected out-of-range rate to fail")
|
|
}
|
|
}
|
|
|
|
func TestLoadDotEnv(t *testing.T) {
|
|
const loaded = "VOICE_TEST_DOTENV_LOADED"
|
|
old, existed := os.LookupEnv(loaded)
|
|
os.Unsetenv(loaded)
|
|
defer func() {
|
|
if existed {
|
|
os.Setenv(loaded, old)
|
|
} else {
|
|
os.Unsetenv(loaded)
|
|
}
|
|
}()
|
|
t.Setenv("VOICE_TEST_DOTENV_EXISTING", "system")
|
|
path := filepath.Join(t.TempDir(), ".env")
|
|
if err := os.WriteFile(path, []byte("export "+loaded+"=\"hello world\"\nVOICE_TEST_DOTENV_EXISTING=file\n"), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := loadDotEnv(path); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if os.Getenv(loaded) != "hello world" || os.Getenv("VOICE_TEST_DOTENV_EXISTING") != "system" {
|
|
t.Fatal("dotenv loading or environment precedence failed")
|
|
}
|
|
}
|
|
|
|
func TestASRCloseLeavesEventsForReader(t *testing.T) {
|
|
t.Run("bailian", func(t *testing.T) {
|
|
a := newBailianASR("model", agentCfg{})
|
|
a.close()
|
|
a.emit(asrEvent{Typ: "final", Text: "ok"})
|
|
if ev := <-a.events(); ev.Text != "ok" {
|
|
t.Fatalf("event=%+v", ev)
|
|
}
|
|
a.closeUpstream()
|
|
})
|
|
t.Run("volc", func(t *testing.T) {
|
|
v := newVolcASR(agentCfg{})
|
|
v.close()
|
|
v.emit(asrEvent{Typ: "final", Text: "ok"})
|
|
if ev := <-v.events(); ev.Text != "ok" {
|
|
t.Fatalf("event=%+v", ev)
|
|
}
|
|
v.closeUpstream()
|
|
})
|
|
}
|
|
|
|
func TestLLMRequestErrorClosesStream(t *testing.T) {
|
|
text, errs := llmChat(context.Background(), agentCfg{BailianBaseURL: "://"}, nil)
|
|
if _, open := <-text; open {
|
|
t.Fatal("text stream left open after request error")
|
|
}
|
|
if err := <-errs; err == nil {
|
|
t.Fatal("expected request error")
|
|
}
|
|
}
|
|
|
|
func TestInterruptTurn(t *testing.T) {
|
|
s := &session{}
|
|
ctx, cancel, _ := s.startTurn()
|
|
defer cancel()
|
|
s.interruptTurn()
|
|
select {
|
|
case <-ctx.Done():
|
|
default:
|
|
t.Fatal("active turn was not canceled")
|
|
}
|
|
}
|
|
|
|
func TestListClonedVoices(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Header.Get("Authorization") != "Bearer key" {
|
|
t.Fatal("missing authorization")
|
|
}
|
|
w.Write([]byte(`{"output":{"voice_list":[{"voice_id":"clone-ok","status":"OK"},{"voice_id":"clone-building","status":"DEPLOYING"}]}}`))
|
|
}))
|
|
defer server.Close()
|
|
|
|
voices, err := listClonedVoices(context.Background(), agentCfg{BailianKey: "key", VoiceAPIURL: server.URL})
|
|
if err != nil || len(voices) != 1 || voices[0].ID != "clone-ok" {
|
|
t.Fatalf("voices=%+v err=%v", voices, err)
|
|
}
|
|
}
|