storage: postgres per-test isolation

This commit is contained in:
nkanaev
2026-06-19 23:42:51 +01:00
parent ba3034b3cf
commit 06bed5b556

View File

@@ -1,16 +1,32 @@
package tests package tests
import ( import (
"crypto/rand"
"database/sql"
"encoding/hex"
"fmt"
"net/url"
"os"
"testing" "testing"
_ "github.com/lib/pq"
"github.com/nkanaev/yarr/src/storage" "github.com/nkanaev/yarr/src/storage"
) )
func dbtest(t *testing.T, testcase func(t *testing.T, db storage.Storage)) { func dbtest(t *testing.T, testcase func(t *testing.T, db storage.Storage)) {
testurls := map[string]string{ testurls := map[string]string{
"sqlite": ":memory:", "sqlite": ":memory:",
// "postgres": "postgres://postgres:postgres@localhost:5432/yarr_test?sslmode=disable",
} }
if pgUrl := os.Getenv("YARR_POSTGRES_TEST_URL"); pgUrl != "" {
dburl, cleanup, err := createPostgresDB(pgUrl)
if err != nil {
t.Fatalf("failed to create postgres test database: %v", err)
}
t.Cleanup(cleanup)
testurls["postgres"] = dburl
}
for testname, url := range testurls { for testname, url := range testurls {
db, err := storage.New(url) db, err := storage.New(url)
if err != nil { if err != nil {
@@ -21,3 +37,50 @@ func dbtest(t *testing.T, testcase func(t *testing.T, db storage.Storage)) {
}) })
} }
} }
func createPostgresDB(pgUrl string) (string, func(), error) {
u, err := url.Parse(pgUrl)
if err != nil {
return "", nil, err
}
u.Path = "/postgres"
adminConnStr := u.String()
adminDB, err := sql.Open("postgres", adminConnStr)
if err != nil {
return "", nil, fmt.Errorf("admin connect: %w", err)
}
b := make([]byte, 4)
if _, err := rand.Read(b); err != nil {
adminDB.Close()
return "", nil, fmt.Errorf("generate suffix: %w", err)
}
testDBName := "yarr_test_" + hex.EncodeToString(b)
if _, err := adminDB.Exec(fmt.Sprintf(`CREATE DATABASE "%s"`, testDBName)); err != nil {
adminDB.Close()
return "", nil, fmt.Errorf("create database: %w", err)
}
adminDB.Close()
u.Path = "/" + testDBName
testURL := u.String()
cleanup := func() {
dropDB, err := sql.Open("postgres", adminConnStr)
if err != nil {
return
}
defer dropDB.Close()
dropDB.Exec(fmt.Sprintf(
`SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '%s' AND pid <> pg_backend_pid()`,
testDBName,
))
dropDB.Exec(fmt.Sprintf(`DROP DATABASE IF EXISTS "%s"`, testDBName))
}
return testURL, cleanup, nil
}