goyave.dev/goyave/v5@v5.0.0-rc9.0.20240517145003-d3f977d0b9f3/database/database_test.go (about) 1 package database 2 3 import ( 4 "bytes" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 "gorm.io/driver/sqlite" 11 "gorm.io/gorm" 12 "gorm.io/gorm/utils/tests" 13 "goyave.dev/goyave/v5/config" 14 "goyave.dev/goyave/v5/slog" 15 ) 16 17 type DummyDialector struct { 18 tests.DummyDialector 19 DSN string 20 } 21 22 func openDummy(dsn string) gorm.Dialector { 23 return &DummyDialector{ 24 DSN: dsn, 25 } 26 } 27 28 func TestNewDatabase(t *testing.T) { 29 RegisterDialect("dummy", "host={host} port={port} user={username} dbname={name} password={password} {options}", openDummy) 30 RegisterDialect("sqlite3_test", "file:{name}?{options}", sqlite.Open) 31 t.Cleanup(func() { 32 mu.Lock() 33 delete(dialects, "dummy") 34 delete(dialects, "sqlite3_test") 35 mu.Unlock() 36 }) 37 38 t.Run("RegisterDialect_already_exists", func(t *testing.T) { 39 assert.Panics(t, func() { 40 RegisterDialect("dummy", "", openDummy) 41 }) 42 }) 43 44 t.Run("New", func(t *testing.T) { 45 cfg := config.LoadDefault() 46 cfg.Set("app.debug", true) 47 cfg.Set("database.connection", "dummy") 48 cfg.Set("database.host", "localhost") 49 cfg.Set("database.port", 5432) 50 cfg.Set("database.name", "dbname") 51 cfg.Set("database.username", "user") 52 cfg.Set("database.password", "secret") 53 cfg.Set("database.options", "option=value") 54 cfg.Set("database.maxOpenConnections", 123) 55 cfg.Set("database.maxIdleConnections", 123) 56 cfg.Set("database.maxLifetime", 123) 57 cfg.Set("database.defaultReadQueryTimeout", 123) 58 cfg.Set("database.defaultWriteQueryTimeout", 123) 59 cfg.Set("database.config.skipDefaultTransaction", true) 60 cfg.Set("database.config.dryRun", true) 61 cfg.Set("database.config.prepareStmt", false) 62 cfg.Set("database.config.disableNestedTransaction", true) 63 cfg.Set("database.config.allowGlobalUpdate", true) 64 cfg.Set("database.config.disableAutomaticPing", true) 65 cfg.Set("database.config.disableForeignKeyConstraintWhenMigrating", true) 66 67 slogger := slog.New(slog.NewHandler(true, &bytes.Buffer{})) 68 db, err := New(cfg, func() *slog.Logger { return slogger }) 69 require.NoError(t, err) 70 require.NotNil(t, db) 71 72 if assert.NotNil(t, db.Config.Logger) { 73 // Logging is enabled when app.debug is true 74 l, ok := db.Config.Logger.(*Logger) 75 if assert.True(t, ok) { 76 assert.NotNil(t, l.slogger) 77 } 78 } 79 80 dbConfig := db.Config 81 // Can't check log level (gorm logger unexported) 82 assert.True(t, dbConfig.SkipDefaultTransaction) 83 assert.True(t, dbConfig.DryRun) 84 assert.False(t, dbConfig.PrepareStmt) 85 assert.True(t, dbConfig.DisableNestedTransaction) 86 assert.True(t, dbConfig.AllowGlobalUpdate) 87 assert.True(t, dbConfig.DisableAutomaticPing) 88 assert.True(t, dbConfig.DisableAutomaticPing) 89 90 // Cannot check the max open conns, idle conns and lifetime 91 92 plugin, ok := db.Plugins[(&TimeoutPlugin{}).Name()] 93 if assert.True(t, ok) { 94 timeoutPlugin, ok := plugin.(*TimeoutPlugin) 95 if assert.True(t, ok) { 96 assert.Equal(t, 123*time.Millisecond, timeoutPlugin.ReadTimeout) 97 assert.Equal(t, 123*time.Millisecond, timeoutPlugin.WriteTimeout) 98 } 99 } 100 101 }) 102 103 t.Run("silent", func(t *testing.T) { 104 cfg := config.LoadDefault() 105 cfg.Set("app.debug", false) 106 cfg.Set("database.connection", "dummy") 107 cfg.Set("database.host", "localhost") 108 cfg.Set("database.port", 5432) 109 cfg.Set("database.name", "dbname") 110 cfg.Set("database.username", "user") 111 cfg.Set("database.password", "secret") 112 cfg.Set("database.options", "option=value") 113 cfg.Set("database.maxOpenConnections", 123) 114 cfg.Set("database.maxIdleConnections", 123) 115 cfg.Set("database.maxLifetime", 123) 116 cfg.Set("database.defaultReadQueryTimeout", 123) 117 cfg.Set("database.defaultWriteQueryTimeout", 123) 118 cfg.Set("database.config.skipDefaultTransaction", true) 119 cfg.Set("database.config.dryRun", true) 120 cfg.Set("database.config.prepareStmt", false) 121 cfg.Set("database.config.disableNestedTransaction", true) 122 cfg.Set("database.config.allowGlobalUpdate", true) 123 cfg.Set("database.config.disableAutomaticPing", true) 124 cfg.Set("database.config.disableForeignKeyConstraintWhenMigrating", true) 125 126 logger := slog.New(slog.NewHandler(false, &bytes.Buffer{})) 127 db, err := New(cfg, func() *slog.Logger { return logger }) 128 require.NoError(t, err) 129 require.NotNil(t, db) 130 131 if assert.NotNil(t, db.Config.Logger) { 132 // Logging is disable when app.debug is false 133 l, ok := db.Config.Logger.(*Logger) 134 if assert.True(t, ok) { 135 assert.Nil(t, l.slogger) 136 } 137 } 138 }) 139 140 t.Run("NewFromDialector", func(t *testing.T) { 141 cfg := config.LoadDefault() 142 cfg.Set("app.debug", true) 143 cfg.Set("database.connection", "dummy") 144 cfg.Set("database.host", "localhost") 145 cfg.Set("database.port", 5432) 146 cfg.Set("database.name", "dbname") 147 cfg.Set("database.username", "user") 148 cfg.Set("database.password", "secret") 149 cfg.Set("database.options", "option=value") 150 cfg.Set("database.maxOpenConnections", 123) 151 cfg.Set("database.maxIdleConnections", 123) 152 cfg.Set("database.maxLifetime", 123) 153 cfg.Set("database.defaultReadQueryTimeout", 123) 154 cfg.Set("database.defaultWriteQueryTimeout", 123) 155 cfg.Set("database.config.skipDefaultTransaction", true) 156 cfg.Set("database.config.dryRun", true) 157 cfg.Set("database.config.prepareStmt", false) 158 cfg.Set("database.config.disableNestedTransaction", true) 159 cfg.Set("database.config.allowGlobalUpdate", true) 160 cfg.Set("database.config.disableAutomaticPing", true) 161 cfg.Set("database.config.disableForeignKeyConstraintWhenMigrating", true) 162 163 dialector := &DummyDialector{} 164 db, err := NewFromDialector(cfg, nil, dialector) 165 require.NoError(t, err) 166 require.NotNil(t, db) 167 168 dbConfig := db.Config 169 // Can't check log level (gorm logger unexported) 170 assert.True(t, dbConfig.SkipDefaultTransaction) 171 assert.True(t, dbConfig.DryRun) 172 assert.False(t, dbConfig.PrepareStmt) 173 assert.True(t, dbConfig.DisableNestedTransaction) 174 assert.True(t, dbConfig.AllowGlobalUpdate) 175 assert.True(t, dbConfig.DisableAutomaticPing) 176 assert.True(t, dbConfig.DisableAutomaticPing) 177 178 // Cannot check the max open conns, idle conns and lifetime 179 180 plugin, ok := db.Plugins[(&TimeoutPlugin{}).Name()] 181 if assert.True(t, ok) { 182 timeoutPlugin, ok := plugin.(*TimeoutPlugin) 183 if assert.True(t, ok) { 184 assert.Equal(t, 123*time.Millisecond, timeoutPlugin.ReadTimeout) 185 assert.Equal(t, 123*time.Millisecond, timeoutPlugin.WriteTimeout) 186 } 187 } 188 189 }) 190 191 t.Run("New_connection_none", func(t *testing.T) { 192 cfg := config.LoadDefault() 193 cfg.Set("database.connection", "none") 194 db, err := New(cfg, nil) 195 assert.Nil(t, db) 196 require.Error(t, err) 197 assert.Equal(t, "Cannot create DB connection. Database is set to \"none\" in the config", err.Error()) 198 }) 199 200 t.Run("New_unknown_driver", func(t *testing.T) { 201 cfg := config.LoadDefault() 202 cfg.Set("database.connection", "notadriver") 203 db, err := New(cfg, nil) 204 assert.Nil(t, db) 205 require.Error(t, err) 206 assert.Equal(t, "DB Connection \"notadriver\" not supported, forgotten import?", err.Error()) 207 }) 208 209 t.Run("SQLite_query", func(t *testing.T) { 210 cfg := config.LoadDefault() 211 cfg.Set("app.debug", false) 212 cfg.Set("database.connection", "sqlite3_test") 213 cfg.Set("database.name", "database_test.db") 214 cfg.Set("database.options", "mode=memory") 215 216 db, err := New(cfg, nil) 217 require.NoError(t, err) 218 require.NotNil(t, db) 219 220 dbNames := []string{} 221 res := db.Table("pragma_database_list").Select("name").Find(&dbNames) 222 require.NoError(t, res.Error) 223 assert.Equal(t, []string{"main"}, dbNames) 224 }) 225 }