fix(account): isolate destructive PostgreSQL tests
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
package account_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
hub "git.ipao.vip/rogee/creator-hub/internal/environment"
|
||||
)
|
||||
|
||||
// Account tests truncate their fixtures. They must never run in the configured
|
||||
// database schema; always initialize and destroy a separate schema first.
|
||||
func TestMain(m *testing.M) { os.Exit(runAccountTests(m)) }
|
||||
|
||||
func runAccountTests(m *testing.M) (result int) {
|
||||
databaseURL := os.Getenv("CREATORHUB_POSTGRES_TEST_URL")
|
||||
if databaseURL == "" {
|
||||
return m.Run()
|
||||
}
|
||||
fail := func(err error) int {
|
||||
fmt.Fprintln(os.Stderr, "initialize isolated account test schema:", err)
|
||||
return 1
|
||||
}
|
||||
parsed, err := url.Parse(databaseURL)
|
||||
if err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
bytes := make([]byte, 8)
|
||||
if _, err := rand.Read(bytes); err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
schema := "account_test_" + hex.EncodeToString(bytes)
|
||||
db, err := sql.Open("pgx", databaseURL)
|
||||
if err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
defer db.Close()
|
||||
if _, err := db.Exec(`CREATE SCHEMA "` + schema + `"`); err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
defer func() {
|
||||
if _, err := db.Exec(`DROP SCHEMA "` + schema + `" CASCADE`); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "cleanup isolated account test schema:", err)
|
||||
result = 1
|
||||
}
|
||||
}()
|
||||
query := parsed.Query()
|
||||
query.Set("search_path", schema)
|
||||
parsed.RawQuery = query.Encode()
|
||||
store, err := hub.Open(context.Background(), parsed.String())
|
||||
if err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
if err := store.Close(); err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
if err := os.Setenv("CREATORHUB_POSTGRES_TEST_URL", parsed.String()); err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
return m.Run()
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
@@ -126,6 +127,20 @@ func applyHubMigrationsForPhaseATest(t *testing.T, store *Store) {
|
||||
}
|
||||
}
|
||||
|
||||
func resetAccountTestFixtures(t *testing.T, store *Store) {
|
||||
t.Helper()
|
||||
var schema string
|
||||
if err := store.db.QueryRow(`SELECT current_schema()`).Scan(&schema); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.HasPrefix(schema, "account_test_") {
|
||||
t.Fatalf("refusing to clear non-test schema %q", schema)
|
||||
}
|
||||
if _, err := store.db.Exec(`TRUNCATE audit_event, network_exit, social_account, browser_env, gateway RESTART IDENTITY CASCADE`); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateAccountWithoutCookiesSkipsCredentialStore(t *testing.T) {
|
||||
databaseURL := os.Getenv("CREATORHUB_POSTGRES_TEST_URL")
|
||||
if databaseURL == "" {
|
||||
@@ -138,11 +153,7 @@ func TestCreateAccountWithoutCookiesSkipsCredentialStore(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(func() { _ = store.Close() })
|
||||
applyHubMigrationsForPhaseATest(t, store)
|
||||
if _, err := store.db.ExecContext(ctx, `
|
||||
TRUNCATE audit_event, network_exit, social_account, browser_env,
|
||||
gateway RESTART IDENTITY CASCADE`); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resetAccountTestFixtures(t, store)
|
||||
credentials := &testCredentialBridge{values: map[string]string{}}
|
||||
account := Account{ID: "account-no-cookies", Name: "扫码账号", Platform: "douyin", PlatformAccountKey: "qr-login",
|
||||
Tags: []string{}, Cookies: "",
|
||||
@@ -168,11 +179,7 @@ func TestAccountCredentialCommitResult(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
applyHubMigrationsForPhaseATest(t, store)
|
||||
if _, err := store.db.ExecContext(ctx, `
|
||||
TRUNCATE audit_event, network_exit, social_account, browser_env,
|
||||
gateway RESTART IDENTITY CASCADE`); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resetAccountTestFixtures(t, store)
|
||||
credentials := &testCredentialBridge{values: map[string]string{}}
|
||||
account := func(id, platformKey string) Account {
|
||||
return Account{ID: id, Name: id, Platform: "douyin", PlatformAccountKey: platformKey, Tags: []string{}, Cookies: "sessionid=" + id,
|
||||
@@ -240,11 +247,7 @@ func TestAccountStoreLifecycleAgainstPostgres(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = store.Close() })
|
||||
if _, err := store.db.ExecContext(ctx, `
|
||||
TRUNCATE audit_event, network_exit, social_account, browser_env,
|
||||
gateway RESTART IDENTITY CASCADE`); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resetAccountTestFixtures(t, store)
|
||||
credentials := &testCredentialBridge{values: map[string]string{}}
|
||||
mustCreate := func(id, platformKey string) {
|
||||
t.Helper()
|
||||
|
||||
Reference in New Issue
Block a user