Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1233f44c8b |
+2
-5
@@ -32,12 +32,9 @@ 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.
|
||||||
# -race also turns on Go's unsafe-pointer checks (checkptr) in every
|
RUN go test -p 4 -timeout 90s -race -cover ./... || \
|
||||||
# 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 -gcflags='modernc.org/...=-d=checkptr=0' -v ./...; exit 1; }
|
go test -p 4 -timeout 90s -race -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
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ package handlers_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -22,6 +25,7 @@ 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"
|
||||||
@@ -37,9 +41,76 @@ 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 (
|
||||||
@@ -84,6 +155,7 @@ 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
|
||||||
|
|
||||||
@@ -109,6 +181,8 @@ 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
|
||||||
|
|||||||
Reference in New Issue
Block a user