@@ -25,29 +25,24 @@ type Fixture struct {
2525 Params []interface {}
2626}
2727
28- type Pgpool interface {
29- // WithFixtures creates database from template database, and initializes it
30- // with fixtures from `fixtures` array
31- WithFixtures (t testing.TB , fixtures []Fixture ) (* pgxpool.Pool , func ())
32- // WithSQLs creates database from template database, and initializes it
33- // with fixtures from `sqls` array
34- WithSQLs (t testing.TB , sqls []string ) (* pgxpool.Pool , func ())
35- // WithEmpty creates empty database from template database, that was
36- // created from `schema` file.
37- WithEmpty (t testing.TB ) (* pgxpool.Pool , func ())
28+ type Pgpool struct {
29+ // BaseName is the prefix of template and temporary databases.
30+ // Default is dbtestpg.
31+ BaseName string
32+ // Name of schema file. Required. Tests would fail if not set.
33+ SchemaFile string // schema file name
34+ // If true, skip all database tests.
35+ Skip bool
36+
37+ m sync.RWMutex
38+ err error
39+ tmpl string
40+ rnd * rand.Rand
3841}
3942
40- type pgpool struct {
41- m sync.RWMutex
42- err error
43- uri string
44- baseName string
45- schema string // schema file name
46- tmpl string
47- rnd * rand.Rand
48- }
49-
50- func (p * pgpool ) WithFixtures (
43+ // WithFixtures creates database from template database, and initializes it
44+ // with fixtures from `fixtures` array
45+ func (p * Pgpool ) WithFixtures (
5146 t testing.TB ,
5247 fixtures []Fixture ,
5348) (* pgxpool.Pool , func ()) {
@@ -66,7 +61,9 @@ func (p *pgpool) WithFixtures(
6661 return pool , clean
6762}
6863
69- func (p * pgpool ) WithSQLs (t testing.TB , sqls []string ) (* pgxpool.Pool , func ()) {
64+ // WithSQLs creates database from template database, and initializes it
65+ // with fixtures from `sqls` array
66+ func (p * Pgpool ) WithSQLs (t testing.TB , sqls []string ) (* pgxpool.Pool , func ()) {
7067 pool , clean := p .WithEmpty (t )
7168 ctx , cancel := context .WithTimeout (context .Background (), defaultTimeout )
7269 defer cancel ()
@@ -82,11 +79,13 @@ func (p *pgpool) WithSQLs(t testing.TB, sqls []string) (*pgxpool.Pool, func()) {
8279 return pool , clean
8380}
8481
85- func (p * pgpool ) getTmpl (t testing.TB ) string {
86- if p .uri == "" {
87- t .Skip ("database uri is not set" )
88- }
82+ func (p * Pgpool ) getTmpl (t testing.TB ) string {
8983 t .Helper ()
84+
85+ if p .Skip {
86+ t .Skip ("Skip database tests" )
87+ }
88+
9089 p .m .RLock ()
9190 err := p .err
9291 tmpl := p .tmpl
@@ -100,6 +99,7 @@ func (p *pgpool) getTmpl(t testing.TB) string {
10099 return tmpl
101100 }
102101 p .m .Lock ()
102+ p .rnd = rand .New (rand .NewSource (time .Now ().UnixNano () + int64 (os .Getpid ())))
103103 p .tmpl , p .err = p .createTemplateDB ()
104104 err = p .err
105105 p .m .Unlock ()
@@ -111,14 +111,18 @@ func (p *pgpool) getTmpl(t testing.TB) string {
111111 return p .tmpl
112112}
113113
114- func (p * pgpool ) createRndDB (t testing.TB ) (* pgxpool.Pool , string ) {
114+ func (p * Pgpool ) createRndDB (t testing.TB ) (* pgxpool.Pool , string ) {
115115 tmpl := p .getTmpl (t )
116116 dbName := fmt .Sprintf ("%v_%v" , tmpl , p .rnd .Int31 ())
117+
117118 err := p .createDB (dbName , tmpl )
119+ if err != nil {
120+ t .Fatal (err )
121+ }
118122
119- cfg , err := pgxpool .ParseConfig (p . uri )
123+ cfg , err := pgxpool .ParseConfig ("" )
120124 if err != nil {
121- _ = dropDB (p . uri , dbName )
125+ _ = dropDB (dbName )
122126 t .Fatal (err )
123127 }
124128 cfg .ConnConfig .Database = dbName
@@ -128,19 +132,19 @@ func (p *pgpool) createRndDB(t testing.TB) (*pgxpool.Pool, string) {
128132
129133 pool , err := pgxpool .ConnectConfig (ctx , cfg )
130134 if err != nil {
131- _ = dropDB (p . uri , dbName )
135+ _ = dropDB (dbName )
132136 t .Fatal ()
133137 }
134138
135139 return pool , dbName
136140}
137141
138142func withNewConnection (
139- uri , dbName string ,
143+ dbName string ,
140144 fn func (context.Context , * pgx.Conn ) error ,
141145) (err error ) {
142146 var cfg * pgx.ConnConfig
143- cfg , err = pgx .ParseConfig (uri )
147+ cfg , err = pgx .ParseConfig ("" )
144148 if err != nil {
145149 return errors .WithStack (err )
146150 }
@@ -175,17 +179,19 @@ func withNewConnection(
175179 return err
176180}
177181
178- func dropDB (uri , dbName string ) error {
182+ func dropDB (dbName string ) error {
179183 return withNewConnection (
180- uri , "" ,
184+ "" ,
181185 func (ctx context.Context , conn * pgx.Conn ) error {
182186 _ , err := conn .Exec (ctx , "DROP DATABASE " + quote (dbName ))
183187 return errors .WithStack (err )
184188 },
185189 )
186190}
187191
188- func (p * pgpool ) WithEmpty (t testing.TB ) (* pgxpool.Pool , func ()) {
192+ // WithEmpty creates empty database from template database, that was
193+ // created from `schema` file.
194+ func (p * Pgpool ) WithEmpty (t testing.TB ) (* pgxpool.Pool , func ()) {
189195 pool , dbName := p .createRndDB (t )
190196 return pool , func () {
191197 acquiredConns := pool .Stat ().AcquiredConns ()
@@ -196,40 +202,43 @@ func (p *pgpool) WithEmpty(t testing.TB) (*pgxpool.Pool, func()) {
196202 )
197203 }
198204 pool .Close ()
199- err := dropDB (p . uri , dbName )
205+ err := dropDB (dbName )
200206 if err != nil {
201207 t .Errorf ("Can't drop DB %v: %v" , dbName , err )
202208 }
203209 }
204210}
205211
206- func (p * pgpool ) createDB (name , tmplName string ) error {
212+ func (p * Pgpool ) createDB (name , tmplName string ) error {
207213 query := `CREATE DATABASE ` + quote (name )
208214 if tmplName != "" {
209215 query += ` WITH TEMPLATE ` + quote (tmplName )
210216 }
211217
212218 return withNewConnection (
213- p . uri , "" ,
219+ "" ,
214220 func (ctx context.Context , conn * pgx.Conn ) error {
215221 _ , err := conn .Exec (ctx , query )
216222 return errors .WithStack (err )
217223 },
218224 )
219225}
220226
221- func (p * pgpool ) createTemplateDB () (string , error ) {
222- schemaSql , err := ioutil .ReadFile (p .schema )
227+ func (p * Pgpool ) createTemplateDB () (string , error ) {
228+ if p .SchemaFile == "" {
229+ return "" , errors .New ("SchemaFile is empty" )
230+ }
231+ schemaSql , err := ioutil .ReadFile (p .SchemaFile )
223232 if err != nil {
224233 return "" , errors .WithStack (err )
225234 }
226235 checksum := md5 .Sum (schemaSql )
227236 schemaHex := hex .EncodeToString (checksum [:])
228- tmpl := fmt .Sprintf ("%v_%v" , p .baseName , schemaHex )
237+ tmpl := fmt .Sprintf ("%v_%v" , p .BaseName , schemaHex )
229238
230239 var dbExists bool
231240 err = withNewConnection (
232- p . uri , "" ,
241+ "" ,
233242 func (ctx context.Context , conn * pgx.Conn ) error {
234243 query := `
235244SELECT EXISTS(SELECT 1 FROM pg_database WHERE datname = $1)
@@ -254,15 +263,15 @@ SELECT EXISTS(SELECT 1 FROM pg_database WHERE datname = $1)
254263 }
255264
256265 err = withNewConnection (
257- p . uri , tmpl ,
266+ tmpl ,
258267 func (ctx context.Context , conn * pgx.Conn ) error {
259268 _ , err = conn .Exec (ctx , string (schemaSql ))
260269 return errors .WithStack (err )
261270 },
262271 )
263272
264273 if err != nil {
265- _ = dropDB (p . uri , tmpl )
274+ _ = dropDB (tmpl )
266275 return "" , err
267276 }
268277
@@ -272,24 +281,3 @@ SELECT EXISTS(SELECT 1 FROM pg_database WHERE datname = $1)
272281func quote (name string ) string {
273282 return pgx.Identifier {name }.Sanitize ()
274283}
275-
276- // NewPool create new Pgpool interface. It won't connect to database
277- // until first reuse. `schema` file must exists and be valid SQL script.
278- func NewPool (dbUri , schema , baseName string ) Pgpool {
279- if dbUri != "" {
280- if baseName == "" {
281- panic ("baseName is required if database uri is set" )
282- }
283- if schema == "" {
284- panic ("schema file name is required if database uri is set" )
285- }
286- }
287- return & pgpool {
288- uri : dbUri ,
289- baseName : baseName ,
290- schema : schema ,
291- rnd : rand .New (
292- rand .NewSource (time .Now ().UnixNano () + int64 (os .Getpid ())),
293- ),
294- }
295- }
0 commit comments