refactor(voice): dashscopeErrorToken 收敛到 trace.ErrorToken

令牌守卫的最后一处副本:删掉 voice 本地的 dashscopeErrorToken 与
maxErrorTokenBytes,四个调用点(classifyDashscopeStatus 的 code / request_id、
dashscopeOKBodyError 的 code / type)改调 trace.ErrorToken。守卫实现与原先逐字
同形(TrimSpace、64 字节上限、字母数字与 _ . -),因此零语义变化。

同时修掉一处过期注释:原 dashscopeErrorToken 的文档指向「runtime/model 的
safeErrorToken」——那个符号在本切片里已被删除,注释指向不存在的符号会把下一个人
送去空目录。现在注释与调用点都指向 trace.ErrorToken。

顺带补一条变异可打红的用例:已有用例只断言「令牌形状的 code 被保留」(去掉守卫
照样通过,半张网),新用例断言 4xx 的 code 是散文时连 `code=` 这个键都不出现,
而 status=400 与 request_id 仍在。

验收:go build ./... + go vet ./... + go test -count=1
./internal/runtime/multimodal/voice/... 全绿;变异(code 改回不过守卫)⇒
TestDashscopeTTS_Non200DropsFreeTextCode 变红。
This commit is contained in:
AskaEth committed 2026-10-26 18:48:01 +08:00
1 parent 3001fcc716
commit 5c6f4e50a0
2 files changed
+62 -29

No files matched your search

@@ -0,0 +1,57 @@
package voice
// 本文件钉住 DashScope 错误收口里的**令牌守卫**(trace.ErrorToken):code 与
// request_id 都是上游自由文本面 —— code 在 DashScope 是枚举(InvalidParameter /
// Throttling.RateQuota / Arrearage …),但网关 / 兼容层可以往里塞任何东西。
//
// 已有的用例(TestDashscopeTTS_Non200DropsSpokenText)只断言「令牌形状的 code 被
// 保留」,去掉守卫它照样通过 —— 那是个半张网。这里补上另一半:**不像令牌的 code
// 必须变空串**,而 status / request_id 这些诊断面仍在。
//
// 形状是「把守去掉就变红」:断言的是错误文本,也就是真正进日志的字符串。
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"strings"
"testing"
"git.yeij.top/AskaEth/Cyrene_v2/internal/config"
)
// TestDashscopeTTS_Non200DropsFreeTextCode 4xx 的 code 里放一段散文(带空格与标点)
// ⇒ 该字段整体消失(连 `code=` 这个键都不出现),而 status 400 与 request_id 仍在。
func TestDashscopeTTS_Non200DropsFreeTextCode(t *testing.T) {
t.Parallel()
const prose = "Invalid value: '她刚才说的那句话'"
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte(`{"code":"` + prose + `","request_id":"req-0123456789abcdef"}`))
}))
defer srv.Close()
tts := NewDashscopeTTS(config.VoiceConfig{DashscopeBaseURL: srv.URL, DashscopeAPIKey: "sk"})
_, err := tts.TTS(context.Background(), "随便说点什么")
if err == nil {
t.Fatal("400 却报成功")
}
if !errors.Is(err, ErrProviderFailed) {
t.Fatalf("err = %v, want ErrProviderFailed(熔断口径不变)", err)
}
msg := err.Error()
if strings.Contains(msg, prose) {
t.Fatalf("code 里的散文进了错误:%v", msg)
}
if strings.Contains(msg, "code=") {
t.Fatalf("非令牌形状的 code 没有被丢弃:%v", msg)
}
// 诊断面不能一起丢:状态码与 request_id(对厂商报障时要给的那个)。
for _, want := range []string{"status=400", "req-0123456789abcdef"} {
if !strings.Contains(msg, want) {
t.Fatalf("错误里缺少 %q(诊断面不能一起丢):%v", want, msg)
}
}
}