1 Commits
Author SHA1 Message Date
sneak eb67f2b417 Make the internal/handlers tests fast (closes #113)
check / check (push) Failing after 4s
-race also turns on Go's unsafe-pointer checks (checkptr) in every
package. modernc.org/sqlite is SQLite machine-translated from C into Go,
and every SQL statement the tests run passes through those checks
thousands of times; they were half the CPU time of the internal/handlers
tests. The test phase now turns them off for the modernc.org packages
only. Race detection is unchanged everywhere, and the pointer checks stay
on for this repository's code and every other dependency.

Model: opus-5-5
2026-10-06 19:19:15 +00:00
2 changed files with 6 additions and 77 deletions
+5 -2
View File
@@ -32,9 +32,12 @@ RUN go mod download
COPY . . COPY . .
RUN mkdir -p web/dist && touch web/dist/index.html web/dist/style.css web/dist/app.js RUN mkdir -p web/dist && touch web/dist/index.html web/dist/style.css web/dist/app.js
# -p 4 because test runs on a shared build host cap their parallelism. # -p 4 because test runs on a shared build host cap their parallelism.
RUN go test -p 4 -timeout 90s -race -cover ./... || \ # -race also turns on Go's unsafe-pointer checks (checkptr) in every
# package. In modernc.org, SQLite machine-translated from C, they doubled
# the test time, so they are off there and stay on everywhere else.
RUN go test -p 4 -timeout 90s -race -gcflags='modernc.org/...=-d=checkptr=0' -cover ./... || \
{ echo "--- Rerunning with -v for details ---"; \ { echo "--- Rerunning with -v for details ---"; \
go test -p 4 -timeout 90s -race -v ./...; exit 1; } go test -p 4 -timeout 90s -race -gcflags='modernc.org/...=-d=checkptr=0' -v ./...; exit 1; }
# Build stage. Nothing is wanted from either phase above; the copies # Build stage. Nothing is wanted from either phase above; the copies
# are what make BuildKit build them first, so this stage cannot run # are what make BuildKit build them first, so this stage cannot run
+1 -75
View File
@@ -6,10 +6,7 @@ package handlers_test
import ( import (
"bytes" "bytes"
"context"
"database/sql"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@@ -25,7 +22,6 @@ import (
"go.uber.org/fx" "go.uber.org/fx"
"go.uber.org/fx/fxtest" "go.uber.org/fx/fxtest"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"modernc.org/sqlite"
"sneak.berlin/go/neoirc/internal/broker" "sneak.berlin/go/neoirc/internal/broker"
"sneak.berlin/go/neoirc/internal/config" "sneak.berlin/go/neoirc/internal/config"
"sneak.berlin/go/neoirc/internal/db" "sneak.berlin/go/neoirc/internal/db"
@@ -41,76 +37,9 @@ import (
"sneak.berlin/go/neoirc/pkg/irc" "sneak.berlin/go/neoirc/pkg/irc"
) )
// templateDBURL names the in-memory database TestMain migrates once
// and every test copies; it lasts while TestMain holds it open.
const templateDBURL = "file:template?mode=memory&cache=shared"
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
db.SetBcryptCost(bcrypt.MinCost) db.SetBcryptCost(bcrypt.MinCost)
os.Exit(m.Run())
template, err := sql.Open("sqlite", templateDBURL)
if err != nil {
panic(err)
}
err = db.NewTestDatabaseFromConn(template).
RunMigrations(context.Background())
if err != nil {
panic(err)
}
code := m.Run()
_ = template.Close()
os.Exit(code)
}
// copyTemplateDB creates the in-memory database dbURL as a copy of
// the migrated template, so a test does not migrate the schema
// again. The copy lasts until the test ends.
func copyTemplateDB(t *testing.T, dbURL string) {
t.Helper()
database, err := sql.Open("sqlite", dbURL)
if err != nil {
t.Fatalf("open test db: %v", err)
}
t.Cleanup(func() { _ = database.Close() })
conn, err := database.Conn(t.Context())
if err != nil {
t.Fatalf("connect test db: %v", err)
}
defer func() { _ = conn.Close() }()
err = conn.Raw(func(driverConn any) error {
restorer, ok := driverConn.(interface {
NewRestore(srcURI string) (*sqlite.Backup, error)
})
if !ok {
return errors.ErrUnsupported
}
restore, restoreErr := restorer.NewRestore(templateDBURL)
if restoreErr != nil {
return fmt.Errorf("start restore: %w", restoreErr)
}
_, restoreErr = restore.Step(-1)
if restoreErr != nil {
_ = restore.Finish()
return fmt.Errorf("restore: %w", restoreErr)
}
return restore.Finish()
})
if err != nil {
t.Fatalf("copy template db: %v", err)
}
} }
const ( const (
@@ -155,7 +84,6 @@ func newTestServerWith(
"file:test_%p?mode=memory&cache=shared", "file:test_%p?mode=memory&cache=shared",
t, t,
) )
copyTemplateDB(t, dbURL)
var srv *server.Server var srv *server.Server
@@ -181,8 +109,6 @@ func newTestServerWith(
cfg.DBURL = dbURL cfg.DBURL = dbURL
cfg.Port = 0 cfg.Port = 0
// One line: each line is a database write per new session.
cfg.MOTD = "neoirc test server"
cfg.HashcashBits = hashcashBits cfg.HashcashBits = hashcashBits
cfg.OperName = operName cfg.OperName = operName
cfg.OperPassword = operPassword cfg.OperPassword = operPassword