Files
webhooker/internal/database/database_test.go
T
sneak 7cb3b006fb
check / check (push) Waiting to run
Report or refuse each unusable file webhooker reads (closes #290)
Audit of the files webhooker reads configuration or required state
from. A missing or zero-length database is reported with the "created
a new, empty database" warning and its path: webhooker.db at start,
and a per-webhook database at the latest at the next start, since
restart recovery now opens the database of every webhook that still
exists. The main database's open errors name webhooker.db
(#459). webhooker resetpw
refuses a zero-length webhooker.db as it refuses a missing one. A
directory in place of a database file or its -wal or -shm is refused,
naming it; beside a -shm directory SQLite opened the database
read-only without a word. The README says how each case is treated.

Model: opus-5-5
2026-10-02 18:50:55 +00:00

128 lines
2.7 KiB
Go

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")
}