package main // 本文件锁定切片 M35 在**组合根**上的三条口径(都是"改坏就静默不工作/静默开错"的那种): // // 1. 面板文件缺失 ⇒ **这一级不启用**,返回的仍是既有链本身(行为逐字不变); // 2. 文件里 `enabled:true` ⇒ 返回 emotionTTS 门面,角色/格式/超时按文件来; // 3. 文件坏掉 ⇒ **不启用**(宁可没有这一级,也不拿读不懂的配置去驱动外部服务)。 // // 它用 `DefaultVoiceTTSPath` 的真实落点($DATA_DIR/config/voice-tts.json)跑, // 因此也钉住"零新 .env 键":没有任何一处读环境变量。 import ( "os" "path/filepath" "testing" "git.yeij.top/AskaEth/Cyrene_v2/internal/config" mvoice "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/multimodal/voice" voicetts "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/voice/tts" ) // voiceTTSApp 造一个只够本题用的 app:数据目录 + 一条既有链。 func voiceTTSApp(t *testing.T) *app { t.Helper() dir := t.TempDir() return &app{ cfg: &config.Config{DataDir: dir}, log: tidyTestLog(), voice: mvoice.New(config.VoiceConfig{}), } } // TestVoiceForGateway_DisabledByDefault 钉住"没配过 ⇒ 原样用既有链"。 func TestVoiceForGateway_DisabledByDefault(t *testing.T) { a := voiceTTSApp(t) got := a.voiceForGateway() if got != any(a.voice) { t.Fatalf("没配过时不该包装既有链: %T", got) } } // TestVoiceForGateway_WrapsWhenEnabled 钉住"文件启用 ⇒ 门面生效 + 配置逐项读对"。 func TestVoiceForGateway_WrapsWhenEnabled(t *testing.T) { a := voiceTTSApp(t) writeVoiceTTSPanel(t, a, `{"enabled":true,"baseUrl":"http://127.0.0.1:9880", "character":"Cyrene","format":"wav","timeoutSec":45}`) got := a.voiceForGateway() svc, ok := got.(*voicetts.Service) if !ok { t.Fatalf("启用后应返回 *tts.Service, got %T", got) } if !svc.PrimaryActive() { t.Fatal("面板写了 enabled:true,但这一级没启用") } if svc.Character() != "Cyrene" { t.Errorf("character = %q, want Cyrene(面板值)", svc.Character()) } } // TestVoiceForGateway_BadFileStaysDisabled 钉住"坏文件 ⇒ 不启用"(绝不半开)。 func TestVoiceForGateway_BadFileStaysDisabled(t *testing.T) { a := voiceTTSApp(t) writeVoiceTTSPanel(t, a, `{"enabled":`) got := a.voiceForGateway() if _, ok := got.(*voicetts.Service); ok { t.Fatal("坏文件却启用了 emotionTTS(会拿读不懂的配置去调外部服务)") } if got != any(a.voice) { t.Fatalf("坏文件时应原样用既有链, got %T", got) } } // TestVoiceTTSConfig_NoEnvKeys 钉住"零新 .env 键":把相关环境变量设成垃圾值, // 配置解析的结果只由面板文件决定(证明它根本没读环境)。 func TestVoiceTTSConfig_NoEnvKeys(t *testing.T) { a := voiceTTSApp(t) t.Setenv("VOICE_TTS_PROVIDER", "emotiontts") t.Setenv("EMOTIONTTS_BASE_URL", "http://evil.invalid") writeVoiceTTSPanel(t, a, `{"enabled":true}`) cfg, enabled := a.voiceTTSConfig() if !enabled { t.Fatal("面板启用却没启用") } if cfg.BaseURL != "" { t.Errorf("baseURL = %q,want 空(默认值由 Normalized 补,不读环境)", cfg.BaseURL) } } // writeVoiceTTSPanel 把内容写进**真实落点**($DATA_DIR/config/voice-tts.json)。 func writeVoiceTTSPanel(t *testing.T, a *app, body string) { t.Helper() path := filepath.Join(a.cfg.DataDir, "config", "voice-tts.json") if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { t.Fatalf("mkdir: %v", err) } if err := os.WriteFile(path, []byte(body), 0o600); err != nil { t.Fatalf("write panel: %v", err) } }