119 lines
4.2 KiB
Go
119 lines
4.2 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.ipao.vip/rogee/creator-hub/internal/creator"
|
|
hub "git.ipao.vip/rogee/creator-hub/internal/environment"
|
|
"github.com/gofiber/fiber/v3"
|
|
)
|
|
|
|
func TestPendingEnvironmentLoginRoutesKeepBrowserIdentity(t *testing.T) {
|
|
raw := os.Getenv("CREATORHUB_POSTGRES_TEST_URL")
|
|
if raw == "" {
|
|
t.Skip("set CREATORHUB_POSTGRES_TEST_URL")
|
|
}
|
|
dbURL := isolatedControlPlaneDatabaseURL(t, raw)
|
|
ctx := context.Background()
|
|
hs, err := hub.Open(ctx, dbURL)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer hs.Close()
|
|
cs, err := creator.Open(ctx, dbURL)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer cs.Close()
|
|
alias := ""
|
|
running := false
|
|
logged := false
|
|
creates := 0
|
|
gateway := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
runtime := map[string]any{"id": "login-runtime", "alias": alias, "state": "running", "binding_version": 1, "network_id": "login-network", "node_id": "login-node", "proxy_ready": true}
|
|
switch {
|
|
case r.Method == http.MethodGet && r.URL.Path == "/v1/browsers":
|
|
items := []map[string]any{}
|
|
if running {
|
|
items = append(items, runtime)
|
|
}
|
|
json.NewEncoder(w).Encode(items)
|
|
case r.Method == http.MethodGet && r.URL.Path == "/v1/browsers/"+alias:
|
|
if !running {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
json.NewEncoder(w).Encode(runtime)
|
|
case r.Method == http.MethodPost && r.URL.Path == "/v1/browsers":
|
|
var body map[string]any
|
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if body["profile_id"] != alias || body["alias"] != alias {
|
|
t.Errorf("unstable browser identity: %#v", body)
|
|
}
|
|
running = true
|
|
creates++
|
|
w.WriteHeader(http.StatusCreated)
|
|
json.NewEncoder(w).Encode(runtime)
|
|
case strings.HasSuffix(r.URL.Path, "/douyin/identity"):
|
|
if !logged {
|
|
json.NewEncoder(w).Encode(map[string]string{"status": "manual_login", "reason": "awaiting_login"})
|
|
return
|
|
}
|
|
json.NewEncoder(w).Encode(creator.PlatformIdentity{UID: "99491952055", Nickname: "平台昵称", AvatarURL: "https://example.com/avatar.jpg", DouyinNumber: "1004291301", SecUID: "MS4w-test"})
|
|
case strings.HasSuffix(r.URL.Path, "/douyin/login-qr"):
|
|
json.NewEncoder(w).Encode(map[string]any{"content_type": "image/png", "body_base64": "aGk=", "qr_detected": true})
|
|
default:
|
|
t.Errorf("unexpected native request %s %s", r.Method, r.URL.Path)
|
|
http.NotFound(w, r)
|
|
}
|
|
}))
|
|
defer gateway.Close()
|
|
if _, err := hs.CreateGateway(ctx, "login-gw", gateway.URL, "test-token-login"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
env, err := hs.CreateStandaloneEnv(ctx, "login-gw", hub.Fingerprint{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
alias = env.Alias
|
|
app := fiber.New()
|
|
registerEnvironmentLoginRoutes(app, cs, hs)
|
|
route := "/api/creator/environments/" + alias
|
|
for _, suffix := range []string{"verify", "login-qr"} {
|
|
response := do(app, http.MethodPost, route+"/"+suffix, `{}`)
|
|
if response.Code != http.StatusOK {
|
|
t.Fatalf("%s: %d %s", suffix, response.Code, response.Body.String())
|
|
}
|
|
}
|
|
pending, err := hs.ListPendingEnvironments(ctx)
|
|
if err != nil || len(pending) != 1 || pending[0].ID != env.ID || env.ID < 1 {
|
|
t.Fatalf("pending browser created account or lost its ordering ID: %v %v", pending, err)
|
|
}
|
|
logged = true
|
|
response := do(app, http.MethodPost, route+"/verify", `{}`)
|
|
if response.Code != http.StatusOK {
|
|
t.Fatalf("verify: %d %s", response.Code, response.Body.String())
|
|
}
|
|
var result creator.LoginResult
|
|
if err := json.Unmarshal(response.Body.Bytes(), &result); err != nil || result.AccountID == "" || result.Status != "logged_in" {
|
|
t.Fatalf("login response: %#v %v", result, err)
|
|
}
|
|
bound, err := hs.GetEnvironmentContext(ctx, alias)
|
|
if err != nil || bound.AccountID != result.AccountID || bound.RuntimeID != "login-runtime" || bound.ProfileID != alias || bound.Fingerprint.Seed != env.Fingerprint.Seed || bound.ID != env.ID {
|
|
t.Fatalf("binding changed browser: %#v %v", bound, err)
|
|
}
|
|
response = do(app, http.MethodPost, route+"/verify", `{}`)
|
|
if response.Code != http.StatusOK || creates != 1 {
|
|
t.Fatalf("repeat login recreated browser: creates=%d %d %s", creates, response.Code, response.Body.String())
|
|
}
|
|
}
|