Sybren A. Stüvel a65f234bea Manager: replace GORM database migration with Goose
Replace GORM's auto-migration with Goose. The latter uses hand-written
SQL queries to apply database schema changes, which is safer and easier to
understand than what GORM is doing.
2023-12-14 10:13:40 +01:00

136 lines
3.1 KiB
Go

// Package persistence provides the database interface for Flamenco Manager.
package persistence
// SPDX-License-Identifier: GPL-3.0-or-later
import (
"context"
"database/sql"
"os"
"testing"
"time"
"github.com/glebarez/sqlite"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
"projects.blender.org/studio/flamenco/internal/uuid"
"projects.blender.org/studio/flamenco/pkg/api"
)
// Change this to a filename if you want to run a single test and inspect the
// resulting database.
const TestDSN = "file::memory:"
func CreateTestDB(t *testing.T) (db *DB, closer func()) {
// Delete the SQLite file if it exists on disk.
if _, err := os.Stat(TestDSN); err == nil {
if err := os.Remove(TestDSN); err != nil {
t.Fatalf("unable to remove %s: %v", TestDSN, err)
}
}
var err error
dblogger := NewDBLogger(log.Level(zerolog.TraceLevel).Output(os.Stdout))
// Open the database ourselves, so that we have a low-level connection that
// can be closed when the unit test is done running.
sqliteConn, err := sql.Open(sqlite.DriverName, TestDSN)
if err != nil {
t.Fatalf("opening SQLite connection: %v", err)
}
config := gorm.Config{
Logger: dblogger,
ConnPool: sqliteConn,
NowFunc: nowFunc,
}
db, err = openDBWithConfig(TestDSN, &config)
if err != nil {
t.Fatalf("opening DB: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
err = db.migrate(ctx)
if err != nil {
t.Fatalf("migrating DB: %v", err)
}
closer = func() {
if err := sqliteConn.Close(); err != nil {
t.Fatalf("closing DB: %v", err)
}
}
return db, closer
}
// persistenceTestFixtures creates a test database and returns it and a context.
// Tests should call the returned cancel function when they're done.
func persistenceTestFixtures(t *testing.T, testContextTimeout time.Duration) (context.Context, context.CancelFunc, *DB) {
db, dbCloser := CreateTestDB(t)
var (
ctx context.Context
ctxCancel context.CancelFunc
)
if testContextTimeout > 0 {
ctx, ctxCancel = context.WithTimeout(context.Background(), testContextTimeout)
} else {
ctx = context.Background()
ctxCancel = func() {}
}
cancel := func() {
ctxCancel()
dbCloser()
}
return ctx, cancel, db
}
type WorkerTestFixture struct {
db *DB
ctx context.Context
done func()
worker *Worker
tag *WorkerTag
}
func workerTestFixtures(t *testing.T, testContextTimeout time.Duration) WorkerTestFixture {
ctx, cancel, db := persistenceTestFixtures(t, testContextTimeout)
w := Worker{
UUID: uuid.New(),
Name: "дрон",
Address: "fe80::5054:ff:fede:2ad7",
Platform: "linux",
Software: "3.0",
Status: api.WorkerStatusAwake,
SupportedTaskTypes: "blender,ffmpeg,file-management",
}
wc := WorkerTag{
UUID: uuid.New(),
Name: "arbejdsklynge",
Description: "Worker tag in Danish",
}
require.NoError(t, db.CreateWorker(ctx, &w))
require.NoError(t, db.CreateWorkerTag(ctx, &wc))
return WorkerTestFixture{
db: db,
ctx: ctx,
done: cancel,
worker: &w,
tag: &wc,
}
}