Keep test helpers out of the shipped binary (closes #506)
check / check (push) Successful in 9m44s

The four testing.go files in config, database, middleware and session
are gone. ClearEnvForTest moves to internal/config/configtest as
ClearEnv; the webhook database manager helpers move to
internal/database/databasetest as NewWebhookDBManager and
NewWebhookDBManagerWithLogger, and the middleware's NewForTest to
internal/middleware/middlewaretest as New, both now built through the
production constructors. Tests that wrapped an open main database use
database.Open. The session helpers move into the session package's
export_test.go; the middleware tests build their session through
session.New and age its timestamps instead of using a fake clock.

The session, middleware and webhook database manager now take the
*slog.Logger they log through, so tests in other packages can give
them their own.

Model: opus-5-5
This commit is contained in:
2026-10-06 10:02:49 +00:00
parent 3de345fe6f
commit 342ae4f04d
39 changed files with 342 additions and 330 deletions
+4 -18
View File
@@ -21,6 +21,7 @@ import (
"gorm.io/gorm/clause"
_ "modernc.org/sqlite" // Pure Go SQLite driver.
"sneak.berlin/go/webhooker/internal/database"
"sneak.berlin/go/webhooker/internal/database/databasetest"
"sneak.berlin/go/webhooker/internal/delivery"
"sneak.berlin/go/webhooker/internal/gormlog"
)
@@ -59,29 +60,14 @@ func setupArchiveTest(t *testing.T) *archiveEnv {
dataDir := t.TempDir()
log := archiveTestLogger()
sqlDB, err := sql.Open(
"sqlite",
fmt.Sprintf(
"file:%s?mode=rwc",
filepath.Join(dataDir, "main.db"),
),
)
mainDB, err := database.Open(dataDir, slog.New(slog.DiscardHandler))
require.NoError(t, err)
t.Cleanup(func() { _ = sqlDB.Close() })
gdb, err := gorm.Open(
sqlite.Dialector{Conn: sqlDB},
&gorm.Config{Logger: gormlog.New(slog.New(slog.DiscardHandler))},
)
require.NoError(t, err)
mainDB := database.NewTestDatabase(gdb)
require.NoError(t, mainDB.Migrate())
t.Cleanup(func() { _ = mainDB.Close() })
eng := delivery.NewTestEngineWithDB(
mainDB,
database.NewTestWebhookDBManager(dataDir),
databasetest.NewWebhookDBManager(t, dataDir),
log,
&http.Client{Timeout: 5 * time.Second},
1,
+19 -40
View File
@@ -10,7 +10,6 @@ import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"sync/atomic"
"testing"
@@ -19,12 +18,11 @@ import (
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
_ "modernc.org/sqlite"
"sneak.berlin/go/webhooker/internal/database"
"sneak.berlin/go/webhooker/internal/database/databasetest"
"sneak.berlin/go/webhooker/internal/delivery"
"sneak.berlin/go/webhooker/internal/gormlog"
)
// iSetup holds common integration test dependencies.
@@ -45,12 +43,12 @@ func newISetup(t *testing.T) iSetup {
wDB := iSeedWebhookDB(t, dbMgr, wID)
return iSetup{
MainDB: mainDB,
MainDB: mainDB.DB(),
DBMgr: dbMgr,
WebhookID: wID,
WebhookDB: wDB,
Engine: delivery.NewTestEngineWithDB(
database.NewTestDatabase(mainDB),
mainDB,
dbMgr,
slog.New(slog.NewTextHandler(
os.Stderr,
@@ -64,35 +62,16 @@ func newISetup(t *testing.T) iSetup {
}
}
func iMainDB(t *testing.T) *gorm.DB {
// iMainDB opens a main database through database.Open, the way the
// service opens it, so these tests cannot pass against journal and
// locking settings production does not use.
func iMainDB(t *testing.T) *database.Database {
t.Helper()
dbPath := filepath.Join(
t.TempDir(), "main-test.db",
)
// Opened the way the service opens the main database, so these
// tests cannot pass against journal and locking settings
// production does not use.
sqlDB, err := database.OpenSQLite(
dbPath, database.SQLiteModeCreate,
)
db, err := database.Open(t.TempDir(), slog.New(slog.DiscardHandler))
require.NoError(t, err)
t.Cleanup(func() { _ = sqlDB.Close() })
db, err := gorm.Open(
sqlite.Dialector{Conn: sqlDB},
&gorm.Config{Logger: gormlog.New(slog.New(slog.DiscardHandler))},
)
require.NoError(t, err)
require.NoError(t, db.AutoMigrate(
&database.Webhook{},
&database.Target{},
&database.User{},
&database.Setting{},
))
t.Cleanup(func() { _ = db.Close() })
return db
}
@@ -102,7 +81,7 @@ func iDBManager(
) *database.WebhookDBManager {
t.Helper()
return database.NewTestWebhookDBManager(t.TempDir())
return databasetest.NewWebhookDBManager(t, t.TempDir())
}
func iSeedWebhookDB(
@@ -1154,17 +1133,17 @@ func TestRecoverInFlight_ReportsAMissingWebhookDatabase(t *testing.T) {
mainDB := iMainDB(t)
webhookID := uuid.New().String()
iCreateWebhook(t, mainDB, webhookID, "lost-database")
iCreateWebhook(t, mainDB.DB(), webhookID, "lost-database")
var logs bytes.Buffer
dbMgr := database.NewTestWebhookDBManagerWithLogger(
t.TempDir(), slog.New(slog.NewTextHandler(&logs, nil)),
dbMgr := databasetest.NewWebhookDBManagerWithLogger(
t, t.TempDir(), slog.New(slog.NewTextHandler(&logs, nil)),
)
t.Cleanup(func() { _ = dbMgr.CloseAll() })
engine := delivery.NewTestEngineWithDB(
database.NewTestDatabase(mainDB), dbMgr,
mainDB, dbMgr,
slog.New(slog.DiscardHandler),
&http.Client{Timeout: 5 * time.Second}, 1,
)
@@ -1188,14 +1167,14 @@ func TestRecoverInFlight_SkipsAWebhookDeletedAfterTheListIsRead(
mainDB := iMainDB(t)
webhookID := uuid.New().String()
iCreateWebhook(t, mainDB, webhookID, "deleted-during-recovery")
iCreateWebhook(t, mainDB.DB(), webhookID, "deleted-during-recovery")
// The first query to return is recovery's read of the list of
// webhooks. Deleting the webhook right after it puts the delete
// between that read and the opening of the webhook's database.
deleted := false
require.NoError(t, mainDB.Callback().Query().After("gorm:query").
require.NoError(t, mainDB.DB().Callback().Query().After("gorm:query").
Register("delete-after-list", func(*gorm.DB) {
if deleted {
return
@@ -1203,16 +1182,16 @@ func TestRecoverInFlight_SkipsAWebhookDeletedAfterTheListIsRead(
deleted = true
require.NoError(t, mainDB.Delete(
require.NoError(t, mainDB.DB().Delete(
&database.Webhook{}, "id = ?", webhookID,
).Error)
}))
dbMgr := database.NewTestWebhookDBManager(t.TempDir())
dbMgr := databasetest.NewWebhookDBManager(t, t.TempDir())
t.Cleanup(func() { _ = dbMgr.CloseAll() })
engine := delivery.NewTestEngineWithDB(
database.NewTestDatabase(mainDB), dbMgr,
mainDB, dbMgr,
slog.New(slog.DiscardHandler),
&http.Client{Timeout: 5 * time.Second}, 1,
)
+9 -26
View File
@@ -5,7 +5,6 @@ import (
"context"
"log/slog"
"net/http"
"path/filepath"
"strings"
"sync"
"testing"
@@ -14,11 +13,9 @@ import (
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"sneak.berlin/go/webhooker/internal/database"
"sneak.berlin/go/webhooker/internal/database/databasetest"
"sneak.berlin/go/webhooker/internal/delivery"
"sneak.berlin/go/webhooker/internal/gormlog"
)
// qdAggregateMarker identifies the queue-depth aggregate in the
@@ -49,27 +46,13 @@ func (q *qdSyncBuf) String() string {
// qdMainDB opens a main database whose GORM logger is the service's
// adapter, writing through log.
func qdMainDB(t *testing.T, log *slog.Logger) *gorm.DB {
func qdMainDB(t *testing.T, log *slog.Logger) *database.Database {
t.Helper()
sqlDB, err := database.OpenSQLite(
filepath.Join(t.TempDir(), "main-gormlog.db"),
database.SQLiteModeCreate,
)
db, err := database.Open(t.TempDir(), log)
require.NoError(t, err)
t.Cleanup(func() { _ = sqlDB.Close() })
db, err := gorm.Open(
sqlite.Dialector{Conn: sqlDB},
&gorm.Config{Logger: gormlog.New(log)},
)
require.NoError(t, err)
require.NoError(t, db.AutoMigrate(
&database.Webhook{},
&database.Target{},
))
t.Cleanup(func() { _ = db.Close() })
return db
}
@@ -106,18 +89,18 @@ func TestQueueDepthSample_LogsNoBoundValue(t *testing.T) {
))
mainDB := qdMainDB(t, log)
dbMgr := database.NewTestWebhookDBManagerWithLogger(
t.TempDir(), log,
dbMgr := databasetest.NewWebhookDBManagerWithLogger(
t, t.TempDir(), log,
)
webhookID := uuid.New().String()
webhookDB := iSeedWebhookDB(t, dbMgr, webhookID)
iCreateWebhook(t, mainDB, webhookID, "queue-depth-gormlog")
iCreateWebhook(t, mainDB.DB(), webhookID, "queue-depth-gormlog")
targetID := uuid.New().String()
iCreateTarget(t, mainDB, targetID, webhookID,
iCreateTarget(t, mainDB.DB(), targetID, webhookID,
"queue-depth-gormlog-target", database.TargetTypeHTTP,
iHTTPConfig("https://example.com/hook"), 3,
)
@@ -136,7 +119,7 @@ func TestQueueDepthSample_LogsNoBoundValue(t *testing.T) {
)
engine := delivery.NewTestEngineWithDB(
database.NewTestDatabase(mainDB),
mainDB,
dbMgr,
log,
&http.Client{Timeout: 5 * time.Second},
@@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sneak.berlin/go/webhooker/internal/database"
"sneak.berlin/go/webhooker/internal/database/databasetest"
"sneak.berlin/go/webhooker/internal/delivery"
)
@@ -335,7 +336,7 @@ func TestArchivePathAt(t *testing.T) {
t.Parallel()
dataDir := t.TempDir()
dbMgr := database.NewTestWebhookDBManager(dataDir)
dbMgr := databasetest.NewWebhookDBManager(t, dataDir)
webhook := &database.Webhook{
BaseModel: database.BaseModel{ID: "wh-id"}, Name: "Orders",
}