Files
Cyrene_v2/internal/runtime/multimodal/voice/dashscope_error_test.go
T
AskaEth 5c6f4e50a0 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 变红。
2026-10-26 18:48:01 +08:00

58 lines
2.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}
}
}