package voice // 本文件是 M49 的**出口回归探针**:DashScope 的「HTTP 200 但业务失败」收口里, // error.code / error.type 的守卫已经上移进 trace.UpstreamError —— 本包那处调用点的 // 重复守卫已删除,因此这里的断言直接钉在**构造函数**上(摘掉构造函数的守卫就变红)。 // // 与它相邻的一条(TestDashscopeTTS_Non200DropsFreeTextCode)钉的是另一件事: // DashScope 的 4xx 把错误码放在**顶层** code(构造函数看不见),那一处靠 // UpstreamErrorInfo.SetCode 注入,守卫仍在。两条合起来覆盖这一族的两个面。 import ( "errors" "strings" "testing" ) // TestDashscopeOKBodyError_DropsFreeTextErrorCode 200 报文的 error.code / error.type // 里带散文(TTS 场景下可能是她要念的台词被回显)⇒ 两个字段整体消失,而 status=200 // 与 body_bytes(体积摘要)仍在。 func TestDashscopeOKBodyError_DropsFreeTextErrorCode(t *testing.T) { t.Parallel() const prose = "Invalid value: '她刚才说的那句话'" body := []byte(`{"error":{"code":"` + prose + `","type":"` + prose + `"}}`) err := dashscopeOKBodyError("https://dashscope.example.com/api/v1/services/audio/tts", body) if !errors.Is(err, ErrProviderFailed) { t.Fatalf("err = %v, want ErrProviderFailed(熔断口径不变)", err) } msg := err.Error() if strings.Contains(msg, "她刚才说的那句话") { t.Fatalf("上游 error.code/type 里的散文进了错误:%v", msg) } if strings.Contains(msg, " code=") || strings.Contains(msg, " type=") { t.Fatalf("非令牌形状的 code/type 没有被丢弃:%v", msg) } for _, want := range []string{"status=200", "body_bytes="} { if !strings.Contains(msg, want) { t.Fatalf("错误里缺少 %q(诊断面不能一起丢):%v", want, msg) } } }