owpengram-server/internal/store/postgres/phone_identity_migration_integration_test.go
2026-09-09 02:49:30 +03:00

97 lines
3.4 KiB
Go

package postgres
import (
"context"
"strings"
"testing"
"github.com/jackc/pgx/v5"
"telesrv/internal/domain"
)
func TestPhoneIdentityMigrationCanonicalizesOnlyAfterCompleteAuditPostgres(t *testing.T) {
pool := testPool(t)
ctx := context.Background()
t.Run("canonicalizes national trunk and preserves significant zero", func(t *testing.T) {
tx := beginPhoneIdentityFixtureTx(t, ctx, pool)
defer func() { _ = tx.Rollback(context.Background()) }()
if _, err := tx.Exec(ctx, `
INSERT INTO users(id, phone) VALUES
(1001, '9809981679461'),
(1002, '390212345678'),
($1, $2)`, domain.OfficialSystemUserID, domain.OfficialSystemPhone); err != nil {
t.Fatalf("insert phone fixtures: %v", err)
}
if err := canonicalizeStoredPhoneIdentitiesInTableTx(ctx, tx, pgx.Identifier{"users"}); err != nil {
t.Fatalf("canonicalizeStoredPhoneIdentitiesInTableTx: %v", err)
}
assertFixturePhone(t, ctx, tx, 1001, "989981679461")
assertFixturePhone(t, ctx, tx, 1002, "390212345678")
assertFixturePhone(t, ctx, tx, domain.OfficialSystemUserID, domain.OfficialSystemPhone)
})
t.Run("duplicate canonical identity fails without changing rows", func(t *testing.T) {
tx := beginPhoneIdentityFixtureTx(t, ctx, pool)
defer func() { _ = tx.Rollback(context.Background()) }()
if _, err := tx.Exec(ctx, `
INSERT INTO users(id, phone) VALUES
(2001, '9809981679461'),
(2002, '989981679461')`); err != nil {
t.Fatalf("insert duplicate fixtures: %v", err)
}
err := canonicalizeStoredPhoneIdentitiesInTableTx(ctx, tx, pgx.Identifier{"users"})
if err == nil || !strings.Contains(err.Error(), "users 2001 and 2002 resolve to the same canonical phone") {
t.Fatalf("canonicalize err = %v, want duplicate user IDs", err)
}
assertFixturePhone(t, ctx, tx, 2001, "9809981679461")
assertFixturePhone(t, ctx, tx, 2002, "989981679461")
})
t.Run("invalid ordinary identity remains unreachable without blocking valid rows", func(t *testing.T) {
tx := beginPhoneIdentityFixtureTx(t, ctx, pool)
defer func() { _ = tx.Rollback(context.Background()) }()
const invalidPhone = "legacy-not-a-phone"
if _, err := tx.Exec(ctx, `
INSERT INTO users(id, phone) VALUES
(3001, $1),
(3002, '9809981679461')`, invalidPhone); err != nil {
t.Fatalf("insert invalid fixture: %v", err)
}
if err := canonicalizeStoredPhoneIdentitiesInTableTx(ctx, tx, pgx.Identifier{"users"}); err != nil {
t.Fatalf("canonicalizeStoredPhoneIdentitiesInTableTx: %v", err)
}
assertFixturePhone(t, ctx, tx, 3001, invalidPhone)
assertFixturePhone(t, ctx, tx, 3002, "989981679461")
})
}
func beginPhoneIdentityFixtureTx(t *testing.T, ctx context.Context, pool interface {
Begin(context.Context) (pgx.Tx, error)
}) pgx.Tx {
t.Helper()
tx, err := pool.Begin(ctx)
if err != nil {
t.Fatalf("begin phone identity fixture: %v", err)
}
if _, err := tx.Exec(ctx, `CREATE TEMP TABLE users (id bigint PRIMARY KEY, phone text NOT NULL) ON COMMIT DROP`); err != nil {
_ = tx.Rollback(context.Background())
t.Fatalf("create isolated users fixture: %v", err)
}
return tx
}
func assertFixturePhone(t *testing.T, ctx context.Context, tx pgx.Tx, userID int64, want string) {
t.Helper()
var got string
if err := tx.QueryRow(ctx, `SELECT phone FROM users WHERE id=$1`, userID).Scan(&got); err != nil {
t.Fatalf("read user %d phone: %v", userID, err)
}
if got != want {
t.Fatalf("user %d phone = %q, want %q", userID, got, want)
}
}