Files

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)
}
}