135 lines
4.2 KiB
Go
135 lines
4.2 KiB
Go
package postgresadmin
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"proxy-pool/internal/domain/adminstate"
|
|
)
|
|
|
|
func TestApplyMigrationsValidatesContextAndPool(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if err := ApplyMigrations(context.Background(), nil); !errors.Is(err, adminstate.ErrInvalidCommand) {
|
|
t.Fatalf("ApplyMigrations(nil) error = %v, want ErrInvalidCommand", err)
|
|
}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
if err := ApplyMigrations(ctx, nil); !errors.Is(err, context.Canceled) {
|
|
t.Fatalf("ApplyMigrations(canceled) error = %v, want context.Canceled", err)
|
|
}
|
|
}
|
|
|
|
func TestMigrationsAreOrderedTransactionalAndImmutable(t *testing.T) {
|
|
t.Parallel()
|
|
migrations := Migrations()
|
|
if len(migrations) != 2 {
|
|
t.Fatalf("len(Migrations()) = %d, want 2", len(migrations))
|
|
}
|
|
if migrations[0].Version != 1 || migrations[0].Name != "admin_state" ||
|
|
migrations[1].Version != 2 || migrations[1].Name != "disable_routing" {
|
|
t.Fatalf("migration metadata = %+v", migrations)
|
|
}
|
|
for _, migration := range migrations {
|
|
normalized := strings.TrimSpace(migration.SQL)
|
|
if !strings.HasPrefix(normalized, "BEGIN;") || !strings.HasSuffix(normalized, "COMMIT;") {
|
|
t.Fatalf("migration %d is not transaction wrapped: %q", migration.Version, normalized)
|
|
}
|
|
}
|
|
for index := 1; index < len(migrations); index++ {
|
|
if migrations[index-1].Version >= migrations[index].Version {
|
|
t.Fatalf("migration versions are not strictly increasing: %+v", migrations)
|
|
}
|
|
}
|
|
|
|
migrations[0].SQL = "changed"
|
|
if Migrations()[0].SQL == "changed" {
|
|
t.Fatal("Migrations() returned mutable package storage")
|
|
}
|
|
}
|
|
|
|
func TestRoutingDisableMigrationExtendsOnlyAuditActionConstraint(t *testing.T) {
|
|
t.Parallel()
|
|
lower := strings.ToLower(Migrations()[1].SQL)
|
|
for _, required := range []string{
|
|
"alter table admin_audit_log",
|
|
"drop constraint if exists admin_audit_log_action_check",
|
|
"disable_routing",
|
|
} {
|
|
if !strings.Contains(lower, required) {
|
|
t.Errorf("routing disable migration missing %q", required)
|
|
}
|
|
}
|
|
for _, forbidden := range []string{"create table", "proxy", "credential", "extraction", "ownership", "idempotency"} {
|
|
if strings.Contains(lower, forbidden) {
|
|
t.Errorf("routing disable migration contains forbidden identifier %q", forbidden)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAdminSchemaContainsOnlyManagementTables(t *testing.T) {
|
|
t.Parallel()
|
|
sql := Migrations()[0].SQL
|
|
tablePattern := regexp.MustCompile(`(?im)^CREATE TABLE IF NOT EXISTS ([a-z][a-z0-9_]*)\s*\(`)
|
|
matches := tablePattern.FindAllStringSubmatch(sql, -1)
|
|
tables := make([]string, 0, len(matches))
|
|
for _, match := range matches {
|
|
tables = append(tables, match[1])
|
|
}
|
|
sort.Strings(tables)
|
|
want := []string{
|
|
"admin_audit_log",
|
|
"admin_outbox",
|
|
"config_revisions",
|
|
"control_revisions",
|
|
"routing_admin_state",
|
|
"upstream_admin_state",
|
|
}
|
|
if strings.Join(tables, ",") != strings.Join(want, ",") {
|
|
t.Fatalf("created tables = %v, want %v", tables, want)
|
|
}
|
|
|
|
lower := strings.ToLower(sql)
|
|
for _, forbidden := range []string{
|
|
"proxy_id", "proxy_host", "proxy_port", "credential", "password",
|
|
"extraction_record", "ownership", "idempotency",
|
|
} {
|
|
if strings.Contains(lower, forbidden) {
|
|
t.Errorf("migration contains forbidden detail identifier %q", forbidden)
|
|
}
|
|
}
|
|
for _, destructive := range []string{"drop table", "truncate ", "delete from"} {
|
|
if strings.Contains(lower, destructive) {
|
|
t.Errorf("forward migration contains destructive statement %q", destructive)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAdminSchemaContainsTransactionAndOutboxConstraints(t *testing.T) {
|
|
t.Parallel()
|
|
lower := strings.ToLower(Migrations()[0].SQL)
|
|
for _, required := range []string{
|
|
"revision bigint generated by default as identity primary key",
|
|
"config_version varchar(128) not null unique",
|
|
"checksum char(64) not null",
|
|
"upstreams text[] not null",
|
|
"current_upstream varchar(128) not null",
|
|
"request_id varchar(128) not null",
|
|
"source_ip inet",
|
|
"payload jsonb not null",
|
|
"claim_owner varchar(128)",
|
|
"claim_until timestamptz",
|
|
"published_at timestamptz",
|
|
"foreign key (revision) references control_revisions(revision)",
|
|
"where published_at is null",
|
|
} {
|
|
if !strings.Contains(lower, required) {
|
|
t.Errorf("migration missing required schema fragment %q", required)
|
|
}
|
|
}
|
|
}
|