package main import ( "context" "errors" "strings" "testing" "github.com/jackc/pgx/v5/pgxpool" ) func TestOpenDatabaseRequiresURLAndRunsMigration(t *testing.T) { ctx := context.Background() connectCalls, migrateCalls := 0, 0 connect := func(_ context.Context, url string) (*pgxpool.Pool, error) { connectCalls++ if url != "postgres://test:secret@localhost/test" { t.Errorf("URL = %q", url) } return pgxpool.New(ctx, url) } migrate := func(_ context.Context, _ *pgxpool.Pool) error { migrateCalls++ return nil } if _, err := openDatabase(ctx, " ", connect, migrate); err == nil || !strings.Contains(err.Error(), "DATABASE_URL") { t.Fatalf("未設定 URL のエラー: %v", err) } if connectCalls != 0 || migrateCalls != 0 { t.Fatalf("未設定でも接続・移行された: %d %d", connectCalls, migrateCalls) } pool, err := openDatabase(ctx, "postgres://test:secret@localhost/test", connect, migrate) if err != nil || pool == nil { t.Fatalf("DB 初期化: %v", err) } pool.Close() if connectCalls != 1 || migrateCalls != 1 { t.Fatalf("接続・移行回数: %d %d", connectCalls, migrateCalls) } } func TestOpenDatabaseReportsMigrationFailure(t *testing.T) { ctx := context.Background() pool, err := openDatabase(ctx, "postgres://test:secret@localhost/test", pgxpool.New, func(context.Context, *pgxpool.Pool) error { return errors.New("migration failed") }) if pool != nil || err == nil || !strings.Contains(err.Error(), "migration failed") { t.Fatalf("移行失敗: pool=%v err=%v", pool, err) } } func TestOpenDatabaseReportsConnectionFailureWithoutLeakingURL(t *testing.T) { migrateCalled := false pool, err := openDatabase(context.Background(), "postgres://user:secret@localhost/test", func(context.Context, string) (*pgxpool.Pool, error) { return nil, errors.New("postgres://user:secret@localhost/test: connection refused") }, func(context.Context, *pgxpool.Pool) error { migrateCalled = true return nil }) if pool != nil || err == nil || strings.Contains(err.Error(), "secret") || migrateCalled { t.Fatalf("接続失敗: pool=%v err=%v migrateCalled=%v", pool, err, migrateCalled) } } func TestOpenDatabaseDoesNotExposeInvalidURL(t *testing.T) { _, err := openDatabase(context.Background(), "postgres://user:secret@%", pgxpool.New, func(context.Context, *pgxpool.Pool) error { t.Fatal("移行してはいけない"); return nil }) if err == nil || strings.Contains(err.Error(), "secret") { t.Fatalf("接続 URL の秘匿: %v", err) } }