check / check (push) Waiting to run
USERHOST, VERSION, ADMIN, INFO, TIME, KILL and WALLOPS on both the HTTP API and the IRC listener, and user mode +w. Model: opus-5-5
77 lines
1.5 KiB
Go
77 lines
1.5 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"log/slog"
|
|
"sync/atomic"
|
|
)
|
|
|
|
//nolint:gochecknoglobals // test counter
|
|
var testDBCounter atomic.Int64
|
|
|
|
// NewTestDatabase creates an in-memory database for testing.
|
|
func NewTestDatabase() (*Database, error) {
|
|
counter := testDBCounter.Add(1)
|
|
|
|
dsn := fmt.Sprintf(
|
|
"file:testdb%d?mode=memory"+
|
|
"&cache=shared&_pragma=foreign_keys(1)",
|
|
counter,
|
|
)
|
|
|
|
conn, err := sql.Open("sqlite", dsn)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open test db: %w", err)
|
|
}
|
|
|
|
database := &Database{ //nolint:exhaustruct // test helper, params not needed
|
|
conn: conn,
|
|
log: slog.Default(),
|
|
}
|
|
|
|
err = database.runMigrations(context.Background())
|
|
if err != nil {
|
|
closeErr := conn.Close()
|
|
if closeErr != nil {
|
|
return nil, fmt.Errorf(
|
|
"close after migration failure: %w",
|
|
closeErr,
|
|
)
|
|
}
|
|
|
|
return nil, fmt.Errorf(
|
|
"run test migrations: %w", err,
|
|
)
|
|
}
|
|
|
|
return database, nil
|
|
}
|
|
|
|
// Close closes the underlying database connection.
|
|
func (database *Database) Close() error {
|
|
err := database.conn.Close()
|
|
if err != nil {
|
|
return fmt.Errorf("close database: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ExecForTest runs a raw statement against the test
|
|
// database. Tests use it to install SQLite triggers that
|
|
// force a specific write to fail, so that the atomicity of
|
|
// multi-statement helpers can be exercised.
|
|
func (database *Database) ExecForTest(
|
|
ctx context.Context,
|
|
query string,
|
|
) error {
|
|
_, err := database.conn.ExecContext(ctx, query)
|
|
if err != nil {
|
|
return fmt.Errorf("exec for test: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|