package vision // 本文件是 M52 的出口回归探针:vision 适配器里「把 net/http 的 *url.Error 直接打进 // 错误串」的两处(建请求 / 发送)一律先过 trace.URLCause。 // // 病害形状:`client.Do` 失败时 net/http 包出 // `Post "https://user:***@h/p?access_token=…": dial tcp …` —— 密码被打码,但用户名与 // 整条 query(含凭据/签名)原样在串里;`http.NewRequest` 的解析失败则把整条 base URL // 带出来。这条串会进日志与工单。 // // 断言形状是「把任一处改回 err ⇒ 对应用例变红」:两处各一个用例,且都同时钉住 // 「只少地址、不少原因」(底层原因与 ErrUpstream 哨兵必须还在)。 import ( "context" "errors" "net/http" "strings" "testing" ) const ( urlCauseQuerySecret = "SECRET-2f8a1c" urlCauseUser = "svc-user" urlCauseBadHost = "bad host.example.com" ) func visionURLCauseGoodBase() string { return "https://" + urlCauseUser + ":svc-pass@vision.example.com/v1?access_token=" + urlCauseQuerySecret } func visionURLCauseBadBase() string { return "https://" + urlCauseUser + ":svc-pass@" + urlCauseBadHost + "/v1?access_token=" + urlCauseQuerySecret } // TestDescribeDropsURLFromTransportError 钉住 ask 里 `a.client.Do` 失败那一处。 func TestDescribeDropsURLFromTransportError(t *testing.T) { t.Parallel() ad := newAdapter(visionURLCauseGoodBase()) ad.client = &http.Client{Transport: stubTransport(func(*http.Request) (*http.Response, error) { return nil, errors.New("dial tcp 10.0.0.1:443: connect: connection refused") })} _, err := ad.Describe(context.Background(), ImageRef{Source: SourceBase64, Data: "aGVsbG8="}, "") if err == nil { t.Fatal("want error, got nil") } if strings.Contains(err.Error(), urlCauseQuerySecret) { t.Fatalf("错误串带出了 query 里的凭据:%v", err) } if strings.Contains(err.Error(), urlCauseUser) { t.Fatalf("错误串带出了 userinfo 里的用户名:%v", err) } if !strings.Contains(err.Error(), "connection refused") { t.Fatalf("错误串丢了底层原因(只许少地址):%v", err) } if !errors.Is(err, ErrUpstream) { t.Fatalf("err = %v, want ErrUpstream(分类不许被带偏)", err) } } // TestDescribeDropsURLFromBuildRequestError 钉住 ask 里 `http.NewRequest` 失败那一处。 func TestDescribeDropsURLFromBuildRequestError(t *testing.T) { t.Parallel() ad := newAdapter(visionURLCauseBadBase()) _, err := ad.Describe(context.Background(), ImageRef{Source: SourceBase64, Data: "aGVsbG8="}, "") if err == nil { t.Fatal("want error, got nil") } if strings.Contains(err.Error(), urlCauseQuerySecret) || strings.Contains(err.Error(), urlCauseUser) { t.Fatalf("建请求失败的串带出了 base URL 里的凭据:%v", err) } if !strings.Contains(err.Error(), "invalid character") { t.Fatalf("错误串丢了底层解析原因(只许少地址):%v", err) } if !errors.Is(err, ErrUpstream) { t.Fatalf("err = %v, want ErrUpstream(分类不许被带偏)", err) } }