package api import ( "bytes" "encoding/base64" "encoding/json" "fmt" "io" "net/http" "net/http/httptest" "os" "path/filepath" "strings" "testing" "time" "git.ipao.vip/rogee/creator-hub/internal/account" "git.ipao.vip/rogee/creator-hub/internal/creator" hub "git.ipao.vip/rogee/creator-hub/internal/environment" "github.com/gofiber/fiber/v3" ) func TestOwnedCoversCacheFilesAndReportIndividualFailures(t *testing.T) { databaseURL := os.Getenv("CREATORHUB_POSTGRES_TEST_URL") if databaseURL == "" { t.Skip("set CREATORHUB_POSTGRES_TEST_URL for isolated PostgreSQL coverage") } store, accounts, ctx := openCreatorIntegrationStoreForAPITest(t, databaseURL) owner := account.Account{ ID: "owned-cover-account", Name: "封面账号", Platform: creator.PlatformDouyin, PlatformAccountKey: "12345678901", CredentialReference: account.CredentialReference{ID: "cover-test-credential", Provider: "os_keyring"}, CredentialKey: "creatorhub/owned-cover-account/cookies", } if err := accounts.CreateAccount(ctx, owner, &testCredentialBridge{values: make(map[string]string)}); err != nil { t.Fatal(err) } works := make(map[string]creator.Work) for _, key := range []string{"good", "broken"} { work, _, err := store.UpsertWork(ctx, creator.WorkInput{SourceType: creator.SourceOwned, SourceID: owner.ID, Platform: creator.PlatformDouyin, WorkKey: "owned-cover-" + key, CoverURL: "https://p3-pc-sign.douyinpic.com/" + key + ".png"}, time.Now().UTC()) if err != nil { t.Fatal(err) } works[key] = work } requests := 0 gateway := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/v1/browsers/owned-cover-alias/douyin/image" { http.NotFound(w, r) return } requests++ var payload struct { URL string `json:"url"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { t.Error(err) w.WriteHeader(400) return } if strings.Contains(payload.URL, "broken") { w.WriteHeader(502) _, _ = io.WriteString(w, "image upstream unavailable") return } _ = json.NewEncoder(w).Encode(map[string]any{"status": 200, "content_type": "image/png", "body_base64": base64.StdEncoding.EncodeToString([]byte("owned-cover-bytes"))}) })) t.Cleanup(gateway.Close) browser := creatorGatewayBrowser{gateway: hub.Gateway{Endpoint: gateway.URL, Token: "test-token"}, environment: hub.EnvironmentContext{Env: hub.Env{Alias: "owned-cover-alias"}, RuntimeID: "runtime-cover", RuntimeNetworkID: "network-cover", BindingVersion: 1}} if err := cacheWorkCovers(ctx, store, browser, creator.SourceOwned, owner.ID); err == nil || !strings.Contains(err.Error(), works["broken"].ID) { t.Fatalf("individual failure was hidden: %v", err) } if requests != 2 { t.Fatalf("failure stopped other covers from downloading: %d", requests) } path, err := store.GetWorkCover(ctx, works["good"].ID) if err != nil { t.Fatal(err) } if filepath.Base(filepath.Dir(path)) != owner.PlatformAccountKey || filepath.Base(path) != "owned-cover-good.png" { t.Fatalf("wrong UID/work-ID layout: %s", path) } missing, err := store.ListWorksMissingCover(ctx, creator.SourceOwned, owner.ID) if err != nil || len(missing) != 1 || missing[0].ID != works["broken"].ID { t.Fatalf("cache retry targets: %v %v", missing, err) } app := fiber.New() RegisterCreator(app, store, accounts, nil) response, err := app.Test(httptest.NewRequest(http.MethodGet, fmt.Sprintf("/api/creator/works/%s/cover", works["good"].ID), nil)) if err != nil { t.Fatal(err) } defer response.Body.Close() body, err := io.ReadAll(response.Body) if err != nil || response.StatusCode != 200 || !strings.HasPrefix(response.Header.Get("Content-Type"), "image/png") || !bytes.Equal(body, []byte("owned-cover-bytes")) { t.Fatalf("static cover response: %d %s %q %v", response.StatusCode, response.Header.Get("Content-Type"), body, err) } }