Files
creator-hub/internal/creator/account_uid_binding_test.go
T
rogee f1a62e25de
douyin-release-gate / verify (push) Failing after 4m22s
feat(account): create browser environments before verified login
2026-10-06 05:55:53 +08:00

122 lines
4.4 KiB
Go

package creator
import (
"errors"
"fmt"
"os"
"strings"
"sync"
"testing"
"git.ipao.vip/rogee/creator-hub/internal/account"
)
func TestCreatorFirstLoginBindsUIDAndNeverReplacesIt(t *testing.T) {
store, accounts, ctx := openCreatorIntegrationStore(t)
create := func(id string) {
t.Helper()
err := accounts.CreateAccount(ctx, account.Account{ID: id, Name: id, Platform: "douyin", CredentialReference: account.CredentialReference{ID: id, Provider: "secret_manager"}, CredentialKey: "creatorhub/" + id}, integrationCredentialBridge{})
if err != nil {
t.Fatal(err)
}
if err := store.EnsureAccountProfile(ctx, id); err != nil {
t.Fatal(err)
}
}
create("uid-first")
create("uid-second")
before, err := store.GetAccountProfile(ctx, "uid-first")
if err != nil || before.PlatformAccountKey != "" {
t.Fatalf("new account must be unbound: %#v err=%v", before, err)
}
for i := 0; i < 2; i++ {
result, err := store.RecordVerifiedLoginResult(ctx, "uid-first", "99491952055")
if err != nil || result.Status != "logged_in" || result.ActualKey != "99491952055" {
t.Fatalf("verify %d: %#v err=%v", i, result, err)
}
}
bound, err := accounts.GetAccount(ctx, "uid-first")
if err != nil || bound.PlatformAccountKey != "99491952055" {
t.Fatalf("verified UID was not persisted: %#v err=%v", bound, err)
}
if _, err := store.RecordVerifiedLoginResult(ctx, "uid-first", "123456789"); !errors.Is(err, ErrConflict) || !strings.Contains(err.Error(), "99491952055") || !strings.Contains(err.Error(), "123456789") {
t.Fatalf("mismatch must explain both UIDs: %v", err)
}
if _, err := store.RecordVerifiedLoginResult(ctx, "uid-second", "99491952055"); !errors.Is(err, ErrConflict) || !strings.Contains(err.Error(), "已绑定") {
t.Fatalf("duplicate binding should fail visibly: %v", err)
}
second, err := store.GetAccountProfile(ctx, "uid-second")
if err != nil || second.PlatformAccountKey != "" || second.LoginStatus == "logged_in" {
t.Fatalf("failed bind changed account: %#v err=%v", second, err)
}
}
func TestCreatorConcurrentFirstLoginBindsExactlyOneUID(t *testing.T) {
store, accounts, ctx := openCreatorIntegrationStore(t)
id := "uid-concurrent"
if err := accounts.CreateAccount(ctx, account.Account{ID: id, Name: id, Platform: "douyin", CredentialReference: account.CredentialReference{ID: id, Provider: "secret_manager"}, CredentialKey: "creatorhub/" + id}, integrationCredentialBridge{}); err != nil {
t.Fatal(err)
}
if err := store.EnsureAccountProfile(ctx, id); err != nil {
t.Fatal(err)
}
var wg sync.WaitGroup
outcomes := make(chan error, 2)
for _, uid := range []string{"111111111", "222222222"} {
wg.Add(1)
go func(uid string) {
defer wg.Done()
_, err := store.RecordVerifiedLoginResult(ctx, id, uid)
outcomes <- err
}(uid)
}
wg.Wait()
close(outcomes)
succeeded, conflicts := 0, 0
for err := range outcomes {
if err == nil {
succeeded++
} else if errors.Is(err, ErrConflict) {
conflicts++
} else {
t.Fatal(err)
}
}
if succeeded != 1 || conflicts != 1 {
t.Fatalf("competing logins changed UID more than once: success=%d conflict=%d", succeeded, conflicts)
}
}
func TestUIDMigrationClearsUnverifiedKeysAndPreservesVerifiedUID(t *testing.T) {
store, accounts, ctx := openCreatorIntegrationStore(t)
for i, status := range []string{"logged_in", "needs_login", "manual_required"} {
id := fmt.Sprintf("uid-migration-%d", i)
if err := accounts.CreateAccount(ctx, account.Account{ID: id, Name: id, Platform: "douyin", PlatformAccountKey: fmt.Sprintf("1000000%d", i), CredentialReference: account.CredentialReference{ID: id, Provider: "secret_manager"}, CredentialKey: "creatorhub/" + id}, integrationCredentialBridge{}); err != nil {
t.Fatal(err)
}
if err := store.EnsureAccountProfile(ctx, id); err != nil {
t.Fatal(err)
}
if _, err := store.db.ExecContext(ctx, `UPDATE creator_account_profile SET login_status=$2 WHERE account_id=(SELECT id FROM social_account WHERE account_id=$1)`, id, status); err != nil {
t.Fatal(err)
}
}
migration, err := os.ReadFile("../environment/migrations/1047_account_uid_first_login.sql")
if err != nil {
t.Fatal(err)
}
if _, err := store.db.ExecContext(ctx, string(migration)); err != nil {
t.Fatal(err)
}
for i := 0; i < 3; i++ {
profile, err := store.GetAccountProfile(ctx, fmt.Sprintf("uid-migration-%d", i))
want := ""
if i == 0 {
want = "10000000"
}
if err != nil || profile.PlatformAccountKey != want {
t.Fatalf("migration %d: %#v err=%v", i, profile, err)
}
}
}