handlers: restore db.DB after each test to fix CI/Platform (Go) race failures

mc#975 root cause: TestListDelegationsFromLedger_* and
TestListDelegationsFromActivityLogs_* assign db.DB = mockDB then defer
mockDB.Close(), but never save/restore the previous db.DB value. With
go test -race (parallel execution), any test running after one of these
13 tests sees db.DB pointing at a closed sqlmock and fails.

Fix: save prevDB := db.DB before assignment, then t.Cleanup(func() {
mockDB.Close(); db.DB = prevDB }) — the same pattern already used by
setupTestDB for the SSRF/restore path.

Also fix setupTestDB in handlers_test.go: it called t.Cleanup(func()
{ mockDB.Close() }) but left db.DB pointing at the closed mock; now it
also restores prevDB.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Molecule AI · core-devops 2026-05-14 09:03:55 +00:00
parent 1b3c0402ab
commit 5531b471d1
2 changed files with 36 additions and 14 deletions

View File

@ -23,8 +23,9 @@ func TestListDelegationsFromLedger_EmptyResult(t *testing.T) {
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
defer mockDB.Close()
prevDB := db.DB
db.DB = mockDB
t.Cleanup(func() { mockDB.Close(); db.DB = prevDB })
rows := sqlmock.NewRows([]string{})
mock.ExpectQuery("SELECT .+ FROM delegations").
@ -49,8 +50,9 @@ func TestListDelegationsFromLedger_SingleRow(t *testing.T) {
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
defer mockDB.Close()
prevDB := db.DB
db.DB = mockDB
t.Cleanup(func() { mockDB.Close(); db.DB = prevDB })
now := time.Now()
rows := sqlmock.NewRows([]string{}).AddRow(
@ -102,8 +104,9 @@ func TestListDelegationsFromLedger_MultipleRows(t *testing.T) {
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
defer mockDB.Close()
prevDB := db.DB
db.DB = mockDB
t.Cleanup(func() { mockDB.Close(); db.DB = prevDB })
now := time.Now()
rows := sqlmock.NewRows([]string{}).
@ -137,8 +140,9 @@ func TestListDelegationsFromLedger_NullsOmitted(t *testing.T) {
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
defer mockDB.Close()
prevDB := db.DB
db.DB = mockDB
t.Cleanup(func() { mockDB.Close(); db.DB = prevDB })
now := time.Now()
rows := sqlmock.NewRows([]string{}).
@ -179,8 +183,9 @@ func TestListDelegationsFromLedger_QueryError(t *testing.T) {
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
defer mockDB.Close()
prevDB := db.DB
db.DB = mockDB
t.Cleanup(func() { mockDB.Close(); db.DB = prevDB })
mock.ExpectQuery("SELECT .+ FROM delegations").
WithArgs("ws-1").
@ -205,8 +210,9 @@ func TestListDelegationsFromLedger_RowsErr(t *testing.T) {
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
defer mockDB.Close()
prevDB := db.DB
db.DB = mockDB
t.Cleanup(func() { mockDB.Close(); db.DB = prevDB })
now := time.Now()
rows := sqlmock.NewRows([]string{}).
@ -237,8 +243,9 @@ func TestListDelegationsFromLedger_ScanError(t *testing.T) {
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
defer mockDB.Close()
prevDB := db.DB
db.DB = mockDB
t.Cleanup(func() { mockDB.Close(); db.DB = prevDB })
now := time.Now()
// Wrong column count → scan error
@ -281,8 +288,9 @@ func TestListDelegationsFromActivityLogs_EmptyResult(t *testing.T) {
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
defer mockDB.Close()
prevDB := db.DB
db.DB = mockDB
t.Cleanup(func() { mockDB.Close(); db.DB = prevDB })
rows := sqlmock.NewRows([]string{})
mock.ExpectQuery("SELECT .+ FROM activity_logs").
@ -307,8 +315,9 @@ func TestListDelegationsFromActivityLogs_SingleDelegateRow(t *testing.T) {
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
defer mockDB.Close()
prevDB := db.DB
db.DB = mockDB
t.Cleanup(func() { mockDB.Close(); db.DB = prevDB })
now := time.Now()
rows := sqlmock.NewRows([]string{}).AddRow(
@ -360,8 +369,9 @@ func TestListDelegationsFromActivityLogs_DelegateResultWithError(t *testing.T) {
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
defer mockDB.Close()
prevDB := db.DB
db.DB = mockDB
t.Cleanup(func() { mockDB.Close(); db.DB = prevDB })
now := time.Now()
rows := sqlmock.NewRows([]string{}).AddRow(
@ -409,8 +419,9 @@ func TestListDelegationsFromActivityLogs_QueryError(t *testing.T) {
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
defer mockDB.Close()
prevDB := db.DB
db.DB = mockDB
t.Cleanup(func() { mockDB.Close(); db.DB = prevDB })
mock.ExpectQuery("SELECT .+ FROM activity_logs").
WithArgs("ws-1").
@ -435,8 +446,9 @@ func TestListDelegationsFromActivityLogs_RowsErr(t *testing.T) {
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
defer mockDB.Close()
prevDB := db.DB
db.DB = mockDB
t.Cleanup(func() { mockDB.Close(); db.DB = prevDB })
now := time.Now()
rows := sqlmock.NewRows([]string{}).
@ -464,8 +476,9 @@ func TestListDelegationsFromActivityLogs_ScanErrorSkipped(t *testing.T) {
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
defer mockDB.Close()
prevDB := db.DB
db.DB = mockDB
t.Cleanup(func() { mockDB.Close(); db.DB = prevDB })
now := time.Now()
// Wrong column count → scan error on first row

View File

@ -29,14 +29,23 @@ func init() {
// setupTestDB creates a sqlmock DB and assigns it to the global db.DB.
// It also disables the SSRF URL check so that httptest.NewServer loopback
// URLs and fake hostnames (*.example) used in tests don't trigger rejections.
//
// IMPORTANT: db.DB is saved before assignment and restored via t.Cleanup so
// that tests running after this one are not polluted by a closed mock.
// This is the single root cause of the systemic CI/Platform (Go) failures on
// main HEAD 8026f020 (mc#975).
func setupTestDB(t *testing.T) sqlmock.Sqlmock {
t.Helper()
mockDB, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("failed to create sqlmock: %v", err)
}
prevDB := db.DB // save in case a prior test left a stale value
db.DB = mockDB
t.Cleanup(func() { mockDB.Close() })
t.Cleanup(func() {
mockDB.Close()
db.DB = prevDB // restore so subsequent tests are not polluted
})
// Disable SSRF checks for the duration of this test only. Restore
// the previous state via t.Cleanup so that TestIsSafeURL_* tests