1
1
package testpgx
2
2
3
3
import (
4
+ "bufio"
4
5
"context"
5
6
"database/sql"
6
7
"errors"
@@ -19,8 +20,8 @@ import (
19
20
"github.com/google/uuid"
20
21
"github.com/hashicorp/go-multierror"
21
22
"github.com/jackc/pgx/v4"
22
- "github.com/jackc/pgx/v4/pgxpool"
23
23
24
+ "github.com/jackc/pgx/v4/pgxpool"
24
25
pgxstdlib "github.com/jackc/pgx/v4/stdlib"
25
26
)
26
27
@@ -78,7 +79,7 @@ const (
78
79
testDBUser = "postgres"
79
80
testDBPass = "anypassword"
80
81
81
- defaultPostgresImage = "postgres:14.4 "
82
+ defaultPostgresImage = "postgres:14.6 "
82
83
defaultMaxDBs = 10
83
84
)
84
85
@@ -180,6 +181,31 @@ func New(ctx context.Context, opts ...Option) (*Env, error) {
180
181
return nil , fmt .Errorf ("when getting postgres cid: %w" , err )
181
182
}
182
183
184
+ // Postgres starts up twice, first as an initialization phase, and then for
185
+ // real. See this thread [1] for more info.
186
+ // [1] https://github.com/docker-library/postgres/issues/146
187
+ pgLogCtx , pgLogDone := context .WithCancel (ctx )
188
+ defer pgLogDone ()
189
+ pgLogCmd := exec .CommandContext (pgLogCtx , o .dockerBinaryPath , "logs" , "-f" , cID )
190
+ pgLogs , err := pgLogCmd .StdoutPipe ()
191
+ if err != nil {
192
+ return nil , fmt .Errorf ("failed to get stdout pipe for docker logs: %w" , err )
193
+ }
194
+ if err := pgLogCmd .Start (); err != nil {
195
+ return nil , fmt .Errorf ("failed to start docker logs: %w" , err )
196
+ }
197
+ initDone := make (chan struct {})
198
+ go func () {
199
+ sc := bufio .NewScanner (pgLogs )
200
+ for sc .Scan () {
201
+ if strings .Contains (sc .Text (), "PostgreSQL init process complete; ready for start up." ) {
202
+ break
203
+ }
204
+ }
205
+ close (initDone )
206
+ pgLogDone ()
207
+ }()
208
+
183
209
env := & Env {
184
210
postgresCid : cID ,
185
211
canCreateDB : make (chan struct {}, o .maxDBs ),
@@ -195,6 +221,10 @@ func New(ctx context.Context, opts ...Option) (*Env, error) {
195
221
}
196
222
197
223
err = waitForPostgresToBeReady (ctx , func (ctx context.Context ) error {
224
+ // Don't try to connect until initialization is done. Postgres starts up twice
225
+ // in Docker, the first is just an initialization.
226
+ <- initDone
227
+
198
228
pool , err := pgxpool .Connect (ctx , env .dsn ("" /* dbName */ ))
199
229
if err != nil {
200
230
return fmt .Errorf ("failed to connect to database instance: %w" , err )
0 commit comments