@@ -3,23 +3,31 @@ package local
33import (
44 "context"
55 "fmt"
6+ "hash/fnv"
67 "net/url"
78 "os"
89 "strings"
9- "sync"
1010 "testing"
1111
1212 "github.com/jackc/pgx/v5"
13- "github.com/jackc/pgx/v5/pgxpool "
13+ "golang.org/x/sync/singleflight "
1414
1515 migrate "github.com/sqlc-dev/sqlc/internal/migrations"
16+ "github.com/sqlc-dev/sqlc/internal/pgx/poolcache"
1617 "github.com/sqlc-dev/sqlc/internal/sql/sqlpath"
1718)
1819
19- var postgresPool * pgxpool.Pool
20- var postgresSync sync.Once
20+ var flight singleflight.Group
2121
2222func PostgreSQL (t * testing.T , migrations []string ) string {
23+ return postgreSQL (t , migrations , true )
24+ }
25+
26+ func ReadOnlyPostgreSQL (t * testing.T , migrations []string ) string {
27+ return postgreSQL (t , migrations , false )
28+ }
29+
30+ func postgreSQL (t * testing.T , migrations []string , rw bool ) string {
2331 ctx := context .Background ()
2432 t .Helper ()
2533
@@ -28,65 +36,83 @@ func PostgreSQL(t *testing.T, migrations []string) string {
2836 t .Skip ("POSTGRESQL_SERVER_URI is empty" )
2937 }
3038
31- postgresSync .Do (func () {
32- pool , err := pgxpool .New (ctx , dburi )
33- if err != nil {
34- t .Fatal (err )
35- }
36- postgresPool = pool
37- })
38-
39- if postgresPool == nil {
40- t .Fatalf ("PostgreSQL pool creation failed" )
39+ postgresPool , err := poolcache .New (ctx , dburi )
40+ if err != nil {
41+ t .Fatalf ("PostgreSQL pool creation failed: %s" , err )
4142 }
4243
4344 var seed []string
4445 files , err := sqlpath .Glob (migrations )
4546 if err != nil {
4647 t .Fatal (err )
4748 }
49+
50+ h := fnv .New64 ()
4851 for _ , f := range files {
4952 blob , err := os .ReadFile (f )
5053 if err != nil {
5154 t .Fatal (err )
5255 }
56+ h .Write (blob )
5357 seed = append (seed , migrate .RemoveRollbackStatements (string (blob )))
5458 }
5559
56- uri , err := url .Parse (dburi )
57- if err != nil {
58- t .Fatal (err )
60+ var name string
61+ if rw {
62+ name = fmt .Sprintf ("sqlc_test_%s" , id ())
63+ } else {
64+ name = fmt .Sprintf ("sqlc_test_%x" , h .Sum (nil ))
5965 }
6066
61- name := fmt .Sprintf ("sqlc_test_%s" , id ())
62-
63- if _ , err := postgresPool .Exec (ctx , fmt .Sprintf (`CREATE DATABASE "%s"` , name )); err != nil {
67+ uri , err := url .Parse (dburi )
68+ if err != nil {
6469 t .Fatal (err )
6570 }
66-
6771 uri .Path = name
6872 dropQuery := fmt .Sprintf (`DROP DATABASE IF EXISTS "%s" WITH (FORCE)` , name )
6973
70- t .Cleanup (func () {
71- if _ , err := postgresPool .Exec (ctx , dropQuery ); err != nil {
72- t .Fatal (err )
74+ key := uri .String ()
75+
76+ _ , err , _ = flight .Do (key , func () (interface {}, error ) {
77+ row := postgresPool .QueryRow (ctx ,
78+ fmt .Sprintf (`SELECT datname FROM pg_database WHERE datname = '%s'` , name ))
79+
80+ var datname string
81+ if err := row .Scan (& datname ); err == nil {
82+ t .Logf ("database exists: %s" , name )
83+ return nil , nil
7384 }
74- })
7585
76- conn , err := pgx .Connect (ctx , uri .String ())
77- if err != nil {
78- t .Fatalf ("connect %s: %s" , name , err )
79- }
80- defer conn .Close (ctx )
86+ t .Logf ("creating database: %s" , name )
87+ if _ , err := postgresPool .Exec (ctx , fmt .Sprintf (`CREATE DATABASE "%s"` , name )); err != nil {
88+ return nil , err
89+ }
8190
82- for _ , q := range seed {
83- if len ( strings . TrimSpace ( q )) == 0 {
84- continue
91+ conn , err := pgx . Connect ( ctx , uri . String ())
92+ if err != nil {
93+ return nil , fmt . Errorf ( "connect %s: %s" , name , err )
8594 }
86- if _ , err := conn .Exec (ctx , q ); err != nil {
87- t .Fatalf ("%s: %s" , q , err )
95+ defer conn .Close (ctx )
96+
97+ for _ , q := range seed {
98+ if len (strings .TrimSpace (q )) == 0 {
99+ continue
100+ }
101+ if _ , err := conn .Exec (ctx , q ); err != nil {
102+ return nil , fmt .Errorf ("%s: %s" , q , err )
103+ }
88104 }
105+ return nil , nil
106+ })
107+ if rw || err != nil {
108+ t .Cleanup (func () {
109+ if _ , err := postgresPool .Exec (ctx , dropQuery ); err != nil {
110+ t .Fatalf ("failed cleaning up: %s" , err )
111+ }
112+ })
89113 }
90-
91- return uri .String ()
114+ if err != nil {
115+ t .Fatalf ("create db: %s" , err )
116+ }
117+ return key
92118}
0 commit comments