Keep each test database when the pool replaces its connection (closes #209)
check / check (push) Waiting to run

SQLite deletes a shared in-memory database when its last connection
closes. A query cancelled while it runs makes the pool close its
connection, so a test could lose all its tables and rows at random.

NewTestDatabaseURL in internal/db returns the URL of a new in-memory
database with a random name. It holds one connection to it open until
the test ends. The db, handlers, ircserver, server and service tests
now take their database URL from it.

A new test cancels a query on such a database, checks with a TEMP
table that the connection was replaced, and checks that a row is
still there.

Model: opus-5-5
This commit is contained in:
2026-10-27 10:29:04 +00:00
parent 53009cf9a0
commit 2673cd4ab2
8 changed files with 85 additions and 42 deletions
+30
View File
@@ -2,10 +2,40 @@ package db
import (
"context"
"crypto/rand"
"database/sql"
"log/slog"
"testing"
)
// NewTestDatabaseURL returns the URL of a new, empty in-memory
// database for one test. SQLite deletes an in-memory database when
// its last connection closes. A pool closes a connection when a query
// on it is cancelled while it runs. So this function holds a
// connection of its own open until the test ends.
func NewTestDatabaseURL(tb testing.TB) string {
tb.Helper()
// A random name, so that no other test can share the database.
dbURL := "file:" + rand.Text() + "?mode=memory&cache=shared"
pool, err := sql.Open("sqlite", dbURL)
if err != nil {
tb.Fatalf("open test database: %v", err)
}
tb.Cleanup(func() { _ = pool.Close() })
conn, err := pool.Conn(tb.Context())
if err != nil {
tb.Fatalf("connect to test database: %v", err)
}
tb.Cleanup(func() { _ = conn.Close() })
return dbURL
}
// NewTestDatabaseFromConn creates a Database wrapping an
// existing *sql.DB connection. Intended for integration
// tests in other packages.