Skip to content

Commit 5bf56fe

Browse files
authored
feat(fxorm): Prevent connection auto close on test mode (#233)
1 parent f343a93 commit 5bf56fe

File tree

5 files changed

+94
-61
lines changed

5 files changed

+94
-61
lines changed

fxorm/README.md

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,12 @@ type Model struct {
5959

6060
func main() {
6161
fx.New(
62-
fxconfig.FxConfigModule, // load the module dependencies
62+
fxconfig.FxConfigModule, // load the module dependencies
6363
fxlog.FxLogModule,
6464
fxtrace.FxTraceModule,
65-
fxorm.FxOrmModule, // load the module
66-
fx.Invoke(func(db *gorm.DB) { // invoke the orm
67-
db.Create(&Model{Name: "some name"})
65+
fxorm.FxOrmModule, // load the module
66+
fx.Invoke(func(gormDB *gorm.DB) { // invoke the orm
67+
gormDB.Create(&Model{Name: "some name"})
6868
}),
6969
).Run()
7070
}
@@ -91,7 +91,7 @@ app:
9191
modules:
9292
orm:
9393
driver: mysql # driver to use
94-
dsn: "user:pass@tcp(dbhost:3306)/dbname?parseTime=True" # database DSN to connect to
94+
dsn: "user:password@tcp(localhost:3306)/db?parseTime=True" # database DSN to use
9595
config:
9696
dry_run: false # disabled by default
9797
skip_default_transaction: false # disabled by default
@@ -113,7 +113,17 @@ modules:
113113
values: true # by adding or not clear SQL queries parameters values in trace spans, disabled by default
114114
```
115115
116-
See [GORM Config](https://github.com/go-gorm/gorm/blob/master/gorm.go) for more details about the configuration.
116+
See [GORM Config](https://github.com/go-gorm/gorm/blob/master/gorm.go) for more details about the `modules.orm.config` configuration keys.
117+
118+
For security reasons, you should avoid to hardcode DSN sensible parts (like the password) in your config files, you can use the [env vars placeholders](https://github.com/ankorstore/yokai/tree/main/fxconfig#configuration-env-var-placeholders) instead:
119+
120+
```yaml
121+
# ./configs/config.yaml
122+
modules:
123+
orm:
124+
driver: mysql
125+
dsn: "${MYSQL_USER}:${MYSQL_PASSWORD}@tcp(${MYSQL_HOST}:${MYSQL_PORT})/${MYSQL_DATABASE}?parseTime=True"
126+
```
117127

118128
### Auto migrations
119129

@@ -143,8 +153,8 @@ func main() {
143153
fxtrace.FxTraceModule,
144154
fxorm.FxOrmModule, // load the module
145155
fxorm.RunFxOrmAutoMigrate(&Model{}), // run auto migration for Model
146-
fx.Invoke(func(db *gorm.DB) { // invoke the orm
147-
db.Create(&Model{Name: "some name"})
156+
fx.Invoke(func(gormDB *gorm.DB) { // invoke the orm
157+
gormDB.Create(&Model{Name: "some name"})
148158
}),
149159
).Run()
150160
}
@@ -163,17 +173,11 @@ You can disable it in the configuration:
163173

164174
```yaml
165175
# ./configs/config.yaml
166-
app:
167-
name: app
168-
env: dev
169-
version: 0.1.0
170-
debug: false
176+
171177
modules:
172178
orm:
173-
driver: mysql # driver to use
174-
dsn: user:pass@tcp(127.0.0.1:3306)/dbname?parseTime=True" # database DSN to connect to
175179
config:
176-
skip_default_transaction: true # disable default transaction
180+
skip_default_transaction: true # disable default transaction
177181
```
178182

179183
#### Cache Prepared Statement
@@ -182,17 +186,10 @@ To create a prepared statement when executing any SQL (and cache them to speed u
182186

183187
```yaml
184188
# ./configs/config.yaml
185-
app:
186-
name: app
187-
env: dev
188-
version: 0.1.0
189-
debug: false
190189
modules:
191190
orm:
192-
driver: mysql # driver to use
193-
dsn: user:pass@tcp(127.0.0.1:3306)/dbname?parseTime=True" # database DSN to connect to
194191
config:
195-
prepare_stmt: true # enable prepared statements
192+
prepare_stmt: true # enable prepared statements
196193
```
197194

198195
### Override

fxorm/module.go

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,6 @@ type FxOrmParam struct {
3636
TracerProvider trace.TracerProvider
3737
}
3838

39-
// RunFxOrmAutoMigrate performs auto migrations for a provided list of models.
40-
func RunFxOrmAutoMigrate(models ...any) fx.Option {
41-
return fx.Invoke(func(logger *log.Logger, db *gorm.DB) error {
42-
logger.Info().Msg("starting ORM auto migration")
43-
44-
err := db.AutoMigrate(models...)
45-
if err != nil {
46-
logger.Error().Err(err).Msg("error during ORM auto migration")
47-
48-
return err
49-
}
50-
51-
logger.Info().Msg("ORM auto migration success")
52-
53-
return nil
54-
})
55-
}
56-
5739
// NewFxOrm returns a [gorm.DB].
5840
func NewFxOrm(p FxOrmParam) (*gorm.DB, error) {
5941
ormConfig := gorm.Config{
@@ -80,37 +62,54 @@ func NewFxOrm(p FxOrmParam) (*gorm.DB, error) {
8062

8163
driver := orm.FetchDriver(p.Config.GetString("modules.orm.driver"))
8264

83-
db, err := p.Factory.Create(
65+
gormDB, err := p.Factory.Create(
8466
orm.WithDsn(p.Config.GetString("modules.orm.dsn")),
8567
orm.WithDriver(driver),
8668
orm.WithConfig(ormConfig),
8769
)
88-
8970
if err != nil {
9071
return nil, err
9172
}
9273

9374
if p.Config.GetBool("modules.orm.trace.enabled") {
94-
err = db.Use(plugin.NewOrmTracerPlugin(p.TracerProvider, p.Config.GetBool("modules.orm.trace.values")))
75+
err = gormDB.Use(plugin.NewOrmTracerPlugin(p.TracerProvider, p.Config.GetBool("modules.orm.trace.values")))
9576
if err != nil {
9677
return nil, err
9778
}
9879
}
9980

10081
p.LifeCycle.Append(fx.Hook{
10182
OnStop: func(ctx context.Context) error {
102-
if driver != orm.Sqlite {
103-
ormDb, err := db.DB()
83+
if !p.Config.IsTestEnv() {
84+
db, err := gormDB.DB()
10485
if err != nil {
10586
return err
10687
}
10788

108-
return ormDb.Close()
89+
return db.Close()
10990
}
11091

11192
return nil
11293
},
11394
})
11495

115-
return db, nil
96+
return gormDB, nil
97+
}
98+
99+
// RunFxOrmAutoMigrate performs auto migrations for a provided list of models.
100+
func RunFxOrmAutoMigrate(models ...any) fx.Option {
101+
return fx.Invoke(func(logger *log.Logger, gormDB *gorm.DB) error {
102+
logger.Info().Msg("starting ORM auto migration")
103+
104+
err := gormDB.AutoMigrate(models...)
105+
if err != nil {
106+
logger.Error().Err(err).Msg("error during ORM auto migration")
107+
108+
return err
109+
}
110+
111+
logger.Info().Msg("ORM auto migration success")
112+
113+
return nil
114+
})
116115
}

fxorm/module_test.go

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func (c *fakeT) FailNow() {
3939
}
4040

4141
func TestModuleWithSqliteAndWithLogEnabledWithValuesAndWithTracesEnabledWithValues(t *testing.T) {
42+
t.Setenv("APP_ENV", "test")
4243
t.Setenv("APP_CONFIG_PATH", "testdata/config")
4344
t.Setenv("ORM_DRIVER", "sqlite")
4445
t.Setenv("ORM_DSN", ":memory:")
@@ -50,6 +51,7 @@ func TestModuleWithSqliteAndWithLogEnabledWithValuesAndWithTracesEnabledWithValu
5051

5152
ctx := context.Background()
5253

54+
var gormDB *gorm.DB
5355
var repository *model.TestModelRepository
5456
var logBuffer logtest.TestLogBuffer
5557
var traceExporter tracetest.TestTraceExporter
@@ -68,7 +70,7 @@ func TestModuleWithSqliteAndWithLogEnabledWithValuesAndWithTracesEnabledWithValu
6870
Name: "test",
6971
})
7072
}),
71-
fx.Populate(&repository, &logBuffer, &traceExporter),
73+
fx.Populate(&gormDB, &repository, &logBuffer, &traceExporter),
7274
).RequireStart().RequireStop()
7375

7476
// assert on DB insertion
@@ -102,9 +104,17 @@ func TestModuleWithSqliteAndWithLogEnabledWithValuesAndWithTracesEnabledWithValu
102104
semconv.DBSystemKey.String("sqlite"),
103105
semconv.DBStatementKey.String("INSERT INTO `test_models` (`name`) VALUES (\"test\")"),
104106
)
107+
108+
// close
109+
db, err := gormDB.DB()
110+
assert.NoError(t, err)
111+
112+
err = db.Close()
113+
assert.NoError(t, err)
105114
}
106115

107116
func TestModuleWithSqliteAndWithLogEnabledWithoutValuesAndWithTracesEnabledWithoutValues(t *testing.T) {
117+
t.Setenv("APP_ENV", "test")
108118
t.Setenv("APP_CONFIG_PATH", "testdata/config")
109119
t.Setenv("ORM_DRIVER", "sqlite")
110120
t.Setenv("ORM_DSN", ":memory:")
@@ -116,6 +126,7 @@ func TestModuleWithSqliteAndWithLogEnabledWithoutValuesAndWithTracesEnabledWitho
116126

117127
ctx := context.Background()
118128

129+
var gormDB *gorm.DB
119130
var repository *model.TestModelRepository
120131
var logBuffer logtest.TestLogBuffer
121132
var traceExporter tracetest.TestTraceExporter
@@ -134,7 +145,7 @@ func TestModuleWithSqliteAndWithLogEnabledWithoutValuesAndWithTracesEnabledWitho
134145
Name: "test",
135146
})
136147
}),
137-
fx.Populate(&repository, &logBuffer, &traceExporter),
148+
fx.Populate(&gormDB, &repository, &logBuffer, &traceExporter),
138149
).RequireStart().RequireStop()
139150

140151
// assert on DB insertion
@@ -168,9 +179,17 @@ func TestModuleWithSqliteAndWithLogEnabledWithoutValuesAndWithTracesEnabledWitho
168179
semconv.DBSystemKey.String("sqlite"),
169180
semconv.DBStatementKey.String("INSERT INTO `test_models` (`name`) VALUES (\"?\")"),
170181
)
182+
183+
// close
184+
db, err := gormDB.DB()
185+
assert.NoError(t, err)
186+
187+
err = db.Close()
188+
assert.NoError(t, err)
171189
}
172190

173191
func TestModuleWithSqliteAndWithLogDisabledAndWithTracesDisabled(t *testing.T) {
192+
t.Setenv("APP_ENV", "test")
174193
t.Setenv("APP_CONFIG_PATH", "testdata/config")
175194
t.Setenv("ORM_DRIVER", "sqlite")
176195
t.Setenv("ORM_DSN", ":memory:")
@@ -179,6 +198,7 @@ func TestModuleWithSqliteAndWithLogDisabledAndWithTracesDisabled(t *testing.T) {
179198

180199
ctx := context.Background()
181200

201+
var gormDB *gorm.DB
182202
var repository *model.TestModelRepository
183203
var logBuffer logtest.TestLogBuffer
184204
var traceExporter tracetest.TestTraceExporter
@@ -197,7 +217,7 @@ func TestModuleWithSqliteAndWithLogDisabledAndWithTracesDisabled(t *testing.T) {
197217
Name: "test",
198218
})
199219
}),
200-
fx.Populate(&repository, &logBuffer, &traceExporter),
220+
fx.Populate(&gormDB, &repository, &logBuffer, &traceExporter),
201221
).RequireStart().RequireStop()
202222

203223
// assert on DB insertion
@@ -226,9 +246,17 @@ func TestModuleWithSqliteAndWithLogDisabledAndWithTracesDisabled(t *testing.T) {
226246

227247
// assert on SQL traces
228248
assert.False(t, traceExporter.HasSpan("orm.Create"))
249+
250+
// close
251+
db, err := gormDB.DB()
252+
assert.NoError(t, err)
253+
254+
err = db.Close()
255+
assert.NoError(t, err)
229256
}
230257

231258
func TestModuleWithAutoMigrationError(t *testing.T) {
259+
t.Setenv("APP_ENV", "test")
232260
t.Setenv("APP_CONFIG_PATH", "testdata/config")
233261
t.Setenv("ORM_DRIVER", "sqlite")
234262
t.Setenv("ORM_DSN", ":memory:")
@@ -253,7 +281,7 @@ func TestModuleWithAutoMigrationError(t *testing.T) {
253281
func TestModuleDecoration(t *testing.T) {
254282
t.Setenv("APP_CONFIG_PATH", "testdata/config")
255283

256-
var db *gorm.DB
284+
var gormDB *gorm.DB
257285

258286
fxtest.New(
259287
t,
@@ -262,8 +290,15 @@ func TestModuleDecoration(t *testing.T) {
262290
fxtrace.FxTraceModule,
263291
fxorm.FxOrmModule,
264292
fx.Decorate(factory.NewTestOrmFactory),
265-
fx.Populate(&db),
293+
fx.Populate(&gormDB),
266294
).RequireStart().RequireStop()
267295

268-
assert.True(t, db.DryRun)
296+
assert.True(t, gormDB.DryRun)
297+
298+
// close
299+
db, err := gormDB.DB()
300+
assert.NoError(t, err)
301+
302+
err = db.Close()
303+
assert.NoError(t, err)
269304
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
modules:
2+
log:
3+
level: debug
4+
output: test
5+
trace:
6+
processor:
7+
type: test
8+

fxorm/testdata/config/config.yaml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
app:
22
name: test
33
modules:
4-
log:
5-
level: debug
6-
output: test
7-
trace:
8-
processor:
9-
type: test
104
orm:
115
driver: ${ORM_DRIVER}
126
dsn: ${ORM_DSN}

0 commit comments

Comments
 (0)