package database_test import ( "bytes" "context" "log/slog" "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/fx/fxtest" "sneak.berlin/go/webhooker/internal/config" "sneak.berlin/go/webhooker/internal/database" "sneak.berlin/go/webhooker/internal/globals" "sneak.berlin/go/webhooker/internal/logger" ) const ( // testAppname is the Globals.Appname used in tests. testAppname = "webhooker-test" // testVersion is the Globals.Version used in tests. testVersion = "test" // testContentType is the event content type used in tests. testContentType = "application/json" // testWebhookName is the Webhook.Name used in tests. testWebhookName = "test-webhook" // testForeverLabel is Webhook.RetentionLabel for a retain-forever // webhook. testForeverLabel = "forever" ) func setupTestDB( t *testing.T, ) (*database.Database, *fxtest.Lifecycle) { t.Helper() lc := fxtest.NewLifecycle(t) g := &globals.Globals{ Appname: testAppname, Version: testVersion, } l, err := logger.New( lc, logger.LoggerParams{Globals: g}, ) if err != nil { t.Fatalf("Failed to create logger: %v", err) } c := &config.Config{ DataDir: t.TempDir(), Environment: "dev", } db, err := database.New(lc, database.DatabaseParams{ Config: c, Logger: l, }) if err != nil { t.Fatalf("Failed to create database: %v", err) } return db, lc } func TestDatabaseConnection(t *testing.T) { t.Parallel() db, lc := setupTestDB(t) ctx := context.Background() err := lc.Start(ctx) if err != nil { t.Fatalf("Failed to connect to database: %v", err) } defer func() { stopErr := lc.Stop(ctx) if stopErr != nil { t.Errorf( "Failed to stop lifecycle: %v", stopErr, ) } }() if db.DB() == nil { t.Error("Expected non-nil database connection") } var result int err = db.DB().Raw("SELECT 1").Scan(&result).Error if err != nil { t.Fatalf("Failed to execute test query: %v", err) } if result != 1 { t.Errorf( "Expected query result to be 1, got %d", result, ) } } // TestOpen_UnreadableDatabaseIsNamed pins // https://git.eeqj.de/sneak/webhooker/issues/459: when SQLite cannot // read webhooker.db, the error that stops the server and `webhooker // resetpw` names the file, not only SQLite's own message. func TestOpen_UnreadableDatabaseIsNamed(t *testing.T) { t.Parallel() dir := t.TempDir() path := filepath.Join(dir, database.MainDBFileName) require.NoError(t, os.WriteFile( path, bytes.Repeat([]byte("junk"), 1024), database.SQLiteFilePerm, )) _, err := database.Open(dir, slog.New(slog.DiscardHandler)) require.Error(t, err) assert.Contains(t, err.Error(), path) assert.Contains(t, err.Error(), "file is not a database") }