- 移除小红书:internal/platform/xiaohongshu、controlplane XHS 分支与路由、 browser_gateway XHS 平台模块与处理器、前端平台选项;migration 038 清理 XHS 数据并将 creator_* 平台 CHECK 收紧为 douyin - creator_competitor 新增 follower_count/following_count/aweme_count(仅 接口定义返回,暂不采集回填);列表接口返回 work_count 与 latest_published_at(creator_work_source 聚合 MAX(published_at)) - 导入页账号名称列展示作者头像(share job 列表带出 avatar_url) - 监控账号页改 antd Listy 卡片列表(头像+粉丝/关注/作品/最近发布/同步状态); AccountManagementList 收敛为 owned 专用 - 环境模块清理 browser_version 遗留:migration 034 补齐删列,修复 store.go 中 hub 别名悬空引用,测试 fixture 对齐新 schema
85 lines
3.1 KiB
Go
85 lines
3.1 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"git.ipao.vip/rogee/creator-hub/internal/creator"
|
|
hub "git.ipao.vip/rogee/creator-hub/internal/environment"
|
|
)
|
|
|
|
func TestCreatorGatewayBrowserResolveAndSharePlatformValidation(t *testing.T) {
|
|
environment := hub.EnvironmentContext{Env: hub.Env{Alias: "account-1"}, RuntimeID: "runtime-1", RuntimeNetworkID: "network-1", BindingVersion: 3}
|
|
cases := []struct {
|
|
name string
|
|
status int
|
|
body string
|
|
wantURL string
|
|
wantErr bool
|
|
}{
|
|
{name: "success", status: http.StatusOK, body: `{"url":"https://www.douyin.com/video/1"}`, wantURL: "https://www.douyin.com/video/1"},
|
|
{name: "invalid json", status: http.StatusOK, body: `{`, wantErr: true},
|
|
{name: "empty url", status: http.StatusOK, body: `{"url":""}`, wantErr: true},
|
|
{name: "rejected", status: http.StatusBadGateway, body: `gateway down`, wantErr: true},
|
|
}
|
|
for _, testCase := range cases {
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/v1/browsers/account-1/douyin/resolve" {
|
|
t.Fatalf("resolve path = %q", r.URL.Path)
|
|
}
|
|
w.WriteHeader(testCase.status)
|
|
_, _ = w.Write([]byte(testCase.body))
|
|
}))
|
|
defer server.Close()
|
|
got, err := (creatorGatewayBrowser{gateway: hub.Gateway{Endpoint: server.URL}, environment: environment}).Resolve(context.Background(), "https://www.douyin.com/video/1")
|
|
if (err != nil) != testCase.wantErr || got != testCase.wantURL {
|
|
t.Fatalf("resolve = %q, err = %v", got, err)
|
|
}
|
|
})
|
|
}
|
|
|
|
for _, testCase := range []struct {
|
|
value string
|
|
platform string
|
|
wantErr bool
|
|
}{
|
|
{value: "https://www.douyin.com/video/1", platform: creator.PlatformDouyin},
|
|
{value: "https://v.douyin.com/abc", platform: creator.PlatformDouyin},
|
|
{value: "https://www.xiaohongshu.com/explore/1", wantErr: true},
|
|
{value: "https://xhslink.com/abc", wantErr: true},
|
|
{value: "http://www.douyin.com/video/1", wantErr: true},
|
|
{value: "https://user@www.douyin.com/video/1", wantErr: true},
|
|
{value: "https://www.douyin.com:443/video/1", wantErr: true},
|
|
{value: "https://www.douyin.com/video/1#part", wantErr: true},
|
|
{value: "https://example.com/video/1", wantErr: true},
|
|
} {
|
|
platform, err := competitorSharePlatform(testCase.value)
|
|
if testCase.wantErr {
|
|
if !errors.Is(err, creator.ErrInvalid) {
|
|
t.Errorf("competitorSharePlatform(%q) error = %v", testCase.value, err)
|
|
}
|
|
continue
|
|
}
|
|
if err != nil || platform != testCase.platform {
|
|
t.Errorf("competitorSharePlatform(%q) = %q, %v", testCase.value, platform, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRebindRecoveryErrorPreservesFailureStates(t *testing.T) {
|
|
sentinel := errors.New("rebind failed")
|
|
if got := rebindRecoveryError(true, sentinel); !errors.Is(got, sentinel) {
|
|
t.Fatalf("existing error = %v", got)
|
|
}
|
|
if got := rebindRecoveryError(false, nil); got == nil {
|
|
t.Fatal("incomplete recovery was reported as successful")
|
|
}
|
|
if got := rebindRecoveryError(true, nil); got != nil {
|
|
t.Fatalf("complete recovery error = %v", got)
|
|
}
|
|
}
|