test: add dbtest.ResetDB helper that preserves admin user
Integration tests previously TRUNCATEd the users table at setup, which wiped the operator's admin login every time the suite ran against a Postgres instance shared with their dev environment. This commit: - Adds internal/dbtest/reset.go exposing ResetDB(t, pool) and TestUserPrefix. ResetDB truncates every data table EXCEPT users, then deletes only users whose username starts with TestUserPrefix. - Migrates 9 test files (subsonic/scrobble, subsonic/star, recommendation/candidates, scrobble/queue, similarity/worker, playevents/writer, playsessions/service, api/auth, api/me) to call ResetDB instead of issuing TRUNCATE-with-users. - Renames hardcoded test usernames to use TestUserPrefix so ResetDB cleans them between runs. seedUser in api/auth_test now prefixes internally; existing call sites pass bare names. - Leaves auth/bootstrap_test.go alone — it legitimately tests first-time admin bootstrap and must wipe users. Verified locally: full integration suite with -p 1 runs cleanly under the existing MINSTREL_TEST_DATABASE_URL setup, and the admin row in the shared dev DB survives the run. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
// Package dbtest provides shared helpers for integration tests that need
|
||||
// a clean Postgres state without disturbing the operator's admin user.
|
||||
//
|
||||
// Background: when integration tests run against the same Postgres
|
||||
// instance an operator uses for local dev (a common dev-laptop setup),
|
||||
// a TRUNCATE that includes the users table wipes the operator's admin
|
||||
// login between every test run. To avoid that, tests should:
|
||||
//
|
||||
// 1. Call ResetDB instead of issuing TRUNCATE statements directly. It
|
||||
// truncates every data table EXCEPT users, then deletes only those
|
||||
// users whose username starts with TestUserPrefix.
|
||||
// 2. Always create test user rows with a username that begins with
|
||||
// TestUserPrefix; otherwise those rows survive across runs and
|
||||
// leak into other tests.
|
||||
//
|
||||
// One test legitimately needs to wipe the entire users table:
|
||||
// internal/auth/bootstrap_test.go, which exercises first-time admin
|
||||
// bootstrap. That file does its own TRUNCATE and does not use this
|
||||
// helper.
|
||||
package dbtest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
// TestUserPrefix is the required username prefix for any user row
|
||||
// created by an integration test. ResetDB removes every user matching
|
||||
// this prefix and leaves all others intact.
|
||||
const TestUserPrefix = "test-"
|
||||
|
||||
// dataTables is the union of every non-users table touched by any
|
||||
// integration test in the repo. Truncating the union is harmless for
|
||||
// callers that only care about a subset; truncating tables that don't
|
||||
// exist would error, but every name here corresponds to a migration
|
||||
// that has shipped.
|
||||
var dataTables = []string{
|
||||
"artist_similarity",
|
||||
"track_similarity",
|
||||
"scrobble_queue",
|
||||
"contextual_likes",
|
||||
"general_likes_albums",
|
||||
"general_likes_artists",
|
||||
"general_likes",
|
||||
"play_events",
|
||||
"skip_events",
|
||||
"play_sessions",
|
||||
"sessions",
|
||||
"tracks",
|
||||
"albums",
|
||||
"artists",
|
||||
}
|
||||
|
||||
// ResetDB clears all data tables and removes any user whose username
|
||||
// begins with TestUserPrefix. Users without that prefix (notably the
|
||||
// operator's admin row) are left alone. Calls t.Fatalf on error.
|
||||
func ResetDB(t *testing.T, pool *pgxpool.Pool) {
|
||||
t.Helper()
|
||||
ctx := context.Background()
|
||||
stmt := "TRUNCATE " + strings.Join(dataTables, ", ") + " RESTART IDENTITY CASCADE"
|
||||
if _, err := pool.Exec(ctx, stmt); err != nil {
|
||||
t.Fatalf("dbtest.ResetDB truncate: %v", err)
|
||||
}
|
||||
if _, err := pool.Exec(ctx,
|
||||
"DELETE FROM users WHERE username LIKE $1",
|
||||
TestUserPrefix+"%",
|
||||
); err != nil {
|
||||
t.Fatalf("dbtest.ResetDB delete test users: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user