Chore: Update test database initialization (#81673)
* streamline initialization of test databases, support on-disk sqlite test db * clean up test databases * introduce testsuite helper * use testsuite everywhere we use a test db * update documentation * improve error handling * disable entity integration test until we can figure out locking error
This commit is contained in:
@@ -91,8 +91,8 @@ func ProvideService(cfg *setting.Cfg,
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func ProvideServiceForTests(cfg *setting.Cfg, features featuremgmt.FeatureToggles, migrations registry.DatabaseMigrator) (*SQLStore, error) {
|
||||
return initTestDB(cfg, features, migrations, InitTestDBOpt{EnsureDefaultOrgAndUser: true})
|
||||
func ProvideServiceForTests(t sqlutil.ITestDB, cfg *setting.Cfg, features featuremgmt.FeatureToggles, migrations registry.DatabaseMigrator) (*SQLStore, error) {
|
||||
return initTestDB(t, cfg, features, migrations, InitTestDBOpt{EnsureDefaultOrgAndUser: true})
|
||||
}
|
||||
|
||||
func newSQLStore(cfg *setting.Cfg, engine *xorm.Engine,
|
||||
@@ -145,11 +145,6 @@ func (ss *SQLStore) Migrate(isDatabaseLockingEnabled bool) error {
|
||||
return migrator.Start(isDatabaseLockingEnabled, ss.dbCfg.MigrationLockAttemptTimeout)
|
||||
}
|
||||
|
||||
// Sync syncs changes to the database.
|
||||
func (ss *SQLStore) Sync() error {
|
||||
return ss.engine.Sync2()
|
||||
}
|
||||
|
||||
// Reset resets database state.
|
||||
// If default org and user creation is enabled, it will be ensured they exist in the database.
|
||||
func (ss *SQLStore) Reset() error {
|
||||
@@ -388,16 +383,10 @@ func (ss *SQLStore) RecursiveQueriesAreSupported() (bool, error) {
|
||||
return *ss.recursiveQueriesAreSupported, nil
|
||||
}
|
||||
|
||||
// ITestDB is an interface of arguments for testing db
|
||||
type ITestDB interface {
|
||||
Helper()
|
||||
Fatalf(format string, args ...any)
|
||||
Logf(format string, args ...any)
|
||||
Log(args ...any)
|
||||
}
|
||||
|
||||
var testSQLStoreSetup = false
|
||||
var testSQLStore *SQLStore
|
||||
var testSQLStoreMutex sync.Mutex
|
||||
var testSQLStoreCleanup []func()
|
||||
|
||||
// InitTestDBOpt contains options for InitTestDB.
|
||||
type InitTestDBOpt struct {
|
||||
@@ -407,10 +396,10 @@ type InitTestDBOpt struct {
|
||||
}
|
||||
|
||||
// InitTestDBWithMigration initializes the test DB given custom migrations.
|
||||
func InitTestDBWithMigration(t ITestDB, migration registry.DatabaseMigrator, opts ...InitTestDBOpt) *SQLStore {
|
||||
func InitTestDBWithMigration(t sqlutil.ITestDB, migration registry.DatabaseMigrator, opts ...InitTestDBOpt) *SQLStore {
|
||||
t.Helper()
|
||||
features := getFeaturesForTesting(opts...)
|
||||
store, err := initTestDB(setting.NewCfg(), features, migration, opts...)
|
||||
store, err := initTestDB(t, setting.NewCfg(), features, migration, opts...)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to initialize sql store: %s", err)
|
||||
}
|
||||
@@ -418,20 +407,46 @@ func InitTestDBWithMigration(t ITestDB, migration registry.DatabaseMigrator, opt
|
||||
}
|
||||
|
||||
// InitTestDB initializes the test DB.
|
||||
func InitTestDB(t ITestDB, opts ...InitTestDBOpt) *SQLStore {
|
||||
func InitTestDB(t sqlutil.ITestDB, opts ...InitTestDBOpt) *SQLStore {
|
||||
t.Helper()
|
||||
features := getFeaturesForTesting(opts...)
|
||||
|
||||
store, err := initTestDB(setting.NewCfg(), features, migrations.ProvideOSSMigrations(features), opts...)
|
||||
store, err := initTestDB(t, setting.NewCfg(), features, migrations.ProvideOSSMigrations(features), opts...)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to initialize sql store: %s", err)
|
||||
}
|
||||
return store
|
||||
}
|
||||
|
||||
func InitTestDBWithCfg(t ITestDB, opts ...InitTestDBOpt) (*SQLStore, *setting.Cfg) {
|
||||
store := InitTestDB(t, opts...)
|
||||
return store, store.Cfg
|
||||
func SetupTestDB() {
|
||||
testSQLStoreMutex.Lock()
|
||||
defer testSQLStoreMutex.Unlock()
|
||||
if testSQLStoreSetup {
|
||||
fmt.Printf("ERROR: Test DB already set up, SetupTestDB called twice\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
testSQLStoreSetup = true
|
||||
}
|
||||
|
||||
func CleanupTestDB() {
|
||||
testSQLStoreMutex.Lock()
|
||||
defer testSQLStoreMutex.Unlock()
|
||||
if !testSQLStoreSetup {
|
||||
fmt.Printf("ERROR: Test DB not set up, SetupTestDB not called\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
if testSQLStore != nil {
|
||||
if err := testSQLStore.GetEngine().Close(); err != nil {
|
||||
fmt.Printf("Failed to close testSQLStore engine: %s\n", err)
|
||||
}
|
||||
|
||||
for _, cleanup := range testSQLStoreCleanup {
|
||||
cleanup()
|
||||
}
|
||||
|
||||
testSQLStoreCleanup = []func(){}
|
||||
testSQLStore = nil
|
||||
}
|
||||
}
|
||||
|
||||
func getFeaturesForTesting(opts ...InitTestDBOpt) featuremgmt.FeatureToggles {
|
||||
@@ -450,24 +465,43 @@ func getFeaturesForTesting(opts ...InitTestDBOpt) featuremgmt.FeatureToggles {
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func initTestDB(testCfg *setting.Cfg,
|
||||
func initTestDB(t sqlutil.ITestDB, testCfg *setting.Cfg,
|
||||
features featuremgmt.FeatureToggles,
|
||||
migration registry.DatabaseMigrator,
|
||||
opts ...InitTestDBOpt) (*SQLStore, error) {
|
||||
testSQLStoreMutex.Lock()
|
||||
defer testSQLStoreMutex.Unlock()
|
||||
if !testSQLStoreSetup {
|
||||
t.Fatalf(`
|
||||
|
||||
ERROR: Test DB not set up, are you missing TestMain?
|
||||
|
||||
https://github.com/grafana/grafana/blob/main/contribute/backend/style-guide.md
|
||||
|
||||
Example:
|
||||
|
||||
package mypkg
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/tests/testsuite"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testsuite.Run(m)
|
||||
}
|
||||
|
||||
`)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if len(opts) == 0 {
|
||||
opts = []InitTestDBOpt{{EnsureDefaultOrgAndUser: false, FeatureFlags: []string{}}}
|
||||
}
|
||||
|
||||
if testSQLStore == nil {
|
||||
dbType := migrator.SQLite
|
||||
|
||||
// environment variable present for test db?
|
||||
if db, present := os.LookupEnv("GRAFANA_TEST_DB"); present {
|
||||
dbType = db
|
||||
}
|
||||
dbType := sqlutil.GetTestDBType()
|
||||
|
||||
// set test db config
|
||||
cfg := setting.NewCfg()
|
||||
@@ -482,21 +516,21 @@ func initTestDB(testCfg *setting.Cfg,
|
||||
if _, err := sec.NewKey("type", dbType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch dbType {
|
||||
case "mysql":
|
||||
if _, err := sec.NewKey("connection_string", sqlutil.MySQLTestDB().ConnStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "postgres":
|
||||
if _, err := sec.NewKey("connection_string", sqlutil.PostgresTestDB().ConnStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
if _, err := sec.NewKey("connection_string", sqlutil.SQLite3TestDB().ConnStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
testDB, err := sqlutil.GetTestDB(dbType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := sec.NewKey("connection_string", testDB.ConnStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := sec.NewKey("path", testDB.Path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
testSQLStoreCleanup = append(testSQLStoreCleanup, testDB.Cleanup)
|
||||
|
||||
// useful if you already have a database that you want to use for tests.
|
||||
// cannot just set it on testSQLStore as it overrides the config in Init
|
||||
if _, present := os.LookupEnv("SKIP_MIGRATIONS"); present {
|
||||
@@ -539,24 +573,6 @@ func initTestDB(testCfg *setting.Cfg,
|
||||
if err := testSQLStore.Migrate(false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := testSQLStore.Dialect.TruncateDBTables(engine); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := testSQLStore.Reset(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Make sure the changes are synced, so they get shared with eventual other DB connections
|
||||
// XXX: Why is this only relevant when not skipping migrations?
|
||||
if !testSQLStore.dbCfg.SkipMigrations {
|
||||
if err := testSQLStore.Sync(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return testSQLStore, nil
|
||||
}
|
||||
|
||||
// nolint:staticcheck
|
||||
|
||||
Reference in New Issue
Block a user