fix(acceptance): 物化验收任务的最终媒体

仅对已认证 Acceptance Run 强制下载并持久化 URL 型结果,确保集群外压测端能验证最终视频;普通生产任务继续遵循现有文件存储策略。压测器仅对 Gateway 自有地址做双入口重写,避免向第三方媒体域名泄露验收凭据。\n\n同时修复本地集群重复使用同一快照文件时的幂等复制失败。验证:Go 全量测试、go vet、gofmt、bash -n、ShellCheck 和 git diff --check 通过。
This commit is contained in:
2026-07-31 21:25:42 +08:00
parent 29a9b8c89f
commit add99e5421
6 changed files with 136 additions and 10 deletions
+75 -5
View File
@@ -760,7 +760,7 @@ func pollVideoTask(ctx context.Context, client *http.Client, opts options, taskI
if mediaURL == "" {
return fmt.Errorf("video task %s succeeded without a media URL", taskID)
}
return validateVideoAsset(ctx, client, mediaURL)
return validateVideoAsset(ctx, client, opts, mediaURL, index)
case "failed", "cancelled", "canceled":
return fmt.Errorf("video task %s finished with status %s", taskID, status)
}
@@ -780,15 +780,34 @@ func pollVideoTask(ctx context.Context, client *http.Client, opts options, taskI
func findMediaURL(value any) string {
switch typed := value.(type) {
case map[string]any:
for key, item := range typed {
preferredKeys := []string{"video_url", "url", "data", "content", "output", "result", "upload"}
visited := make(map[string]struct{}, len(typed))
for _, key := range preferredKeys {
item, ok := typed[key]
if !ok {
continue
}
visited[key] = struct{}{}
normalized := strings.ToLower(strings.TrimSpace(key))
if (normalized == "url" || normalized == "video_url") && strings.HasPrefix(strings.TrimSpace(fmt.Sprint(item)), "http") {
if (normalized == "url" || normalized == "video_url") && acceptanceMediaURL(strings.TrimSpace(fmt.Sprint(item))) {
return strings.TrimSpace(fmt.Sprint(item))
}
if mediaURL := findMediaURL(item); mediaURL != "" {
return mediaURL
}
}
keys := make([]string, 0, len(typed)-len(visited))
for key := range typed {
if _, ok := visited[key]; !ok {
keys = append(keys, key)
}
}
sort.Strings(keys)
for _, key := range keys {
if mediaURL := findMediaURL(typed[key]); mediaURL != "" {
return mediaURL
}
}
case []any:
for _, item := range typed {
if mediaURL := findMediaURL(item); mediaURL != "" {
@@ -799,11 +818,22 @@ func findMediaURL(value any) string {
return ""
}
func validateVideoAsset(ctx context.Context, client *http.Client, mediaURL string) error {
request, err := http.NewRequestWithContext(ctx, http.MethodGet, mediaURL, nil)
func acceptanceMediaURL(value string) bool {
return strings.HasPrefix(value, "/") || strings.HasPrefix(value, "http://") || strings.HasPrefix(value, "https://")
}
func validateVideoAsset(ctx context.Context, client *http.Client, opts options, mediaURL string, index int) error {
requestURL, gatewayRequest, err := acceptanceMediaRequestURL(opts, mediaURL, index)
if err != nil {
return fmt.Errorf("resolve final video: %w", err)
}
request, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
if err != nil {
return err
}
if gatewayRequest {
opts.setHeaders(request, index, false)
}
response, err := client.Do(request)
if err != nil {
return fmt.Errorf("download final video: %w", err)
@@ -824,6 +854,46 @@ func validateVideoAsset(ctx context.Context, client *http.Client, mediaURL strin
return nil
}
func acceptanceMediaRequestURL(opts options, mediaURL string, index int) (string, bool, error) {
mediaURL = strings.TrimSpace(mediaURL)
if mediaURL == "" {
return "", false, errors.New("empty media URL")
}
if strings.HasPrefix(mediaURL, "/") {
if len(opts.gateways) == 0 {
return "", false, errors.New("no gateway URL configured")
}
base, err := url.Parse(opts.gateways[index%len(opts.gateways)])
if err != nil {
return "", false, err
}
reference, err := url.Parse(mediaURL)
if err != nil {
return "", false, err
}
return base.ResolveReference(reference).String(), true, nil
}
parsed, err := url.Parse(mediaURL)
if err != nil {
return "", false, err
}
if opts.gatewayTLSName == "" || !strings.EqualFold(parsed.Hostname(), opts.gatewayTLSName) {
return parsed.String(), false, nil
}
if len(opts.gateways) == 0 {
return "", false, errors.New("no gateway URL configured")
}
base, err := url.Parse(opts.gateways[index%len(opts.gateways)])
if err != nil {
return "", false, err
}
base.Path = parsed.Path
base.RawPath = parsed.RawPath
base.RawQuery = parsed.RawQuery
base.Fragment = parsed.Fragment
return base.String(), true, nil
}
func (o options) setHeaders(request *http.Request, requestIndex int, realUpstream bool) {
if o.gatewayTLSName != "" {
request.Host = o.gatewayTLSName