-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoptions.go
212 lines (182 loc) · 5.82 KB
/
options.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
package testdock
import (
"errors"
"fmt"
"os"
"strings"
"time"
"github.com/google/uuid"
"github.com/n-r-w/ctxlog"
)
const (
// DefaultMongoDSN - default mongodb connection string.
DefaultMongoDSN = "mongodb://testuser:secret@127.0.0.1:27017/testdb?authSource=admin"
// DefaultMySQLDSN - default mysql connection string.
DefaultMySQLDSN = "root:secret@tcp(127.0.0.1:3306)/test_db"
// DefaultPostgresDSN - default postgres connection string.
DefaultPostgresDSN = "postgres://postgres:secret@127.0.0.1:5432/postgres?sslmode=disable"
)
// RunMode defines the run mode of the test database.
type RunMode int
const (
// RunModeUnknown - unknown run mode
RunModeUnknown RunMode = 0
// RunModeDocker - run the tests in docker
RunModeDocker RunMode = 1
// RunModeExternal - run the tests in external database
RunModeExternal RunMode = 2
// RunModeAuto - checks the environment variable TESTDOCK_DSN_[DRIVER]. If it is set,
// then RunModeExternal, otherwise RunModeDocker.
// If TESTDOCK_DSN_[DRIVER] is set and RunModeAuto, WithDSN option is ignored.
// For example, for postgres pgx driver:
// TESTDOCK_DSN_PGX=postgres://postgres:secret@localhost:5432/postgres&sslmode=disable
RunModeAuto RunMode = 3
)
// Option option for creating a test database.
type Option func(*testDB)
// WithMode sets the mode for the test database.
// The default is RunModeAuto.
func WithMode(mode RunMode) Option {
return func(o *testDB) {
o.mode = mode
}
}
// WithDockerRepository sets the name of docker hub repository.
// Required for RunModeDocker or RunModeAuto with empty environment variable TESTDOCK_DSN_[DRIVER].
func WithDockerRepository(dockerRepository string) Option {
return func(o *testDB) {
o.dockerRepository = dockerRepository
}
}
// WithDockerImage sets the name of the docker image.
// The default is `latest`.
func WithDockerImage(dockerImage string) Option {
return func(o *testDB) {
o.dockerImage = dockerImage
}
}
// WithDockerSocketEndpoint sets the docker socket endpoint for connecting to the docker daemon.
// The default is autodetect.
func WithDockerSocketEndpoint(dockerSocketEndpoint string) Option {
return func(o *testDB) {
o.dockerSocketEndpoint = dockerSocketEndpoint
}
}
// WithDockerPort sets the port for connecting to database in docker.
// The default is the port from the DSN.
func WithDockerPort(dockerPort int) Option {
return func(o *testDB) {
o.dockerPort = dockerPort
}
}
// WithRetryTimeout sets the timeout for connecting to the database.
// The default is 3 second. Must be less than totalRetryDuration.
func WithRetryTimeout(retryTimeout time.Duration) Option {
return func(o *testDB) {
o.retryTimeout = retryTimeout
}
}
// WithTotalRetryDuration sets the total retry duration.
// The default is 30 seconds. Must be greater than retryTimeout.
func WithTotalRetryDuration(totalRetryDuration time.Duration) Option {
return func(o *testDB) {
o.totalRetryDuration = totalRetryDuration
}
}
// WithLogger sets the logger for the test database.
// The default is logger from testing.TB.
func WithLogger(logger ctxlog.ILogger) Option {
return func(o *testDB) {
o.logger = logger
}
}
// WithMigrations sets the directory and factory for the migrations.
func WithMigrations(migrationsDir string, migrateFactory MigrateFactory) Option {
return func(o *testDB) {
o.migrationsDir = migrationsDir
o.MigrateFactory = migrateFactory
}
}
// WithDockerEnv sets the environment variables for the docker container.
// The default is empty.
func WithDockerEnv(dockerEnv []string) Option {
return func(o *testDB) {
o.dockerEnv = dockerEnv
}
}
// WithUnsetProxyEnv unsets the proxy environment variables.
// The default is false.
func WithUnsetProxyEnv(unsetProxyEnv bool) Option {
return func(o *testDB) {
o.unsetProxyEnv = unsetProxyEnv
}
}
// WithPrepareCleanUp sets the function for prepare to delete temporary test database.
// The default is empty, but `GetPgxPool` and `GetPqConn` use it
// to automatically apply cleanup handlers to disconnect all users from the database
// before cleaning up.
func WithPrepareCleanUp(prepareCleanUp PrepareCleanUp) Option {
return func(o *testDB) {
o.prepareCleanUp = append(o.prepareCleanUp, prepareCleanUp)
}
}
// WithConnectDatabase sets the name of the database to connect to.
// The default will be take from the DSN.
func WithConnectDatabase(connectDatabase string) Option {
return func(o *testDB) {
o.connectDatabase = connectDatabase
o.connectDatabaseOverride = true
}
}
func (d *testDB) prepareOptions(driver string, options []Option) error {
for _, o := range options {
o(d)
}
if d.totalRetryDuration <= d.retryTimeout {
return errors.New("totalRetryDuration must be greater than retryTimeout")
}
if d.driver == "" {
return errors.New("driver is empty")
}
if d.mode == RunModeAuto {
dsnEnv := os.Getenv(fmt.Sprintf("TESTDOCK_DSN_%s", strings.ToUpper(driver)))
if dsnEnv != "" {
d.dsn = dsnEnv
d.mode = RunModeExternal
} else {
d.mode = RunModeDocker
}
}
if d.dsn == "" {
return errors.New("dsn is empty")
}
p, err := parseURL(d.dsn)
if err != nil {
return fmt.Errorf("parse dsn: %w", err)
}
d.url = p
d.dsnNoPass = p.string(true)
if !d.connectDatabaseOverride && d.connectDatabase == "" {
d.connectDatabase = p.Database
}
if d.mode == RunModeDocker {
if d.dockerRepository == "" {
return errors.New("dockerRepository is empty")
}
if d.dockerImage == "" {
d.dockerImage = "latest"
}
if d.dockerPort <= 0 {
d.dockerPort = p.Port
if d.dockerPort <= 0 {
return errors.New("dockerPort must be greater than 0")
}
}
}
dbName := fmt.Sprintf("t_%s_%s", time.Now().Format("2006_0102_1504_05"), uuid.New().String())
d.databaseName = strings.ReplaceAll(dbName, "-", "")
if (d.MigrateFactory == nil) != (d.migrationsDir == "") {
return errors.New("MigrateFactory and migrationsDir must be set together")
}
return nil
}