Move the test-only helpers out of the shipped db package (closes #248)
check / check (push) Waiting to run
check / check (push) Waiting to run
The server binary carried exported names that only tests call, including raw SQL access and a way to weaken the password hash. Delete testing.go, GetDB and SetBcryptCost from the shipped code, so passwords always hash at bcrypt.DefaultCost. Move GetDB, GetOrCreateChannel, JoinChannel and HasChannelInvite into export_test.go. Delete GetClientHostInfo, whose remaining check GetLatestClientForSession covers. Tests in other packages now build the database with db.New and run raw SQL through dbtest.Exec. Handler tests and the relay tests' aliceWithHTTPClient helper need a password only to log in, so they store one hashed at bcrypt.MinCost. Tests of PASS itself keep the real cost. Model: opus-5-5
This commit was merged in pull request #255.
This commit is contained in:
@@ -47,22 +47,25 @@ import (
|
||||
const templateDBURL = "file:template?mode=memory&cache=shared"
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
db.SetBcryptCost(bcrypt.MinCost)
|
||||
template := fx.New(
|
||||
fx.NopLogger,
|
||||
fx.Supply(
|
||||
&globals.Globals{},
|
||||
&config.Config{DBURL: templateDBURL},
|
||||
),
|
||||
fx.Provide(logger.New, newTestDB),
|
||||
// fx makes the database only if something asks for it.
|
||||
fx.Invoke(func(*db.Database) {}),
|
||||
)
|
||||
|
||||
template, err := sql.Open("sqlite", templateDBURL)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = db.NewTestDatabaseFromConn(template).
|
||||
RunMigrations(context.Background())
|
||||
err := template.Start(context.Background())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
code := m.Run()
|
||||
|
||||
_ = template.Close()
|
||||
_ = template.Stop(context.Background())
|
||||
|
||||
os.Exit(code)
|
||||
}
|
||||
@@ -137,6 +140,7 @@ type testServer struct {
|
||||
t *testing.T
|
||||
fxApp *fxtest.App
|
||||
broker *broker.Broker
|
||||
dbURL string
|
||||
database *db.Database
|
||||
handlers *handlers.Handlers
|
||||
}
|
||||
@@ -231,6 +235,7 @@ func newTestServerWith(
|
||||
t: t,
|
||||
fxApp: app,
|
||||
broker: brk,
|
||||
dbURL: dbURL,
|
||||
database: database,
|
||||
handlers: hdlr,
|
||||
}
|
||||
@@ -858,10 +863,7 @@ func TestRequestBodyLimit(t *testing.T) {
|
||||
tserver := newTestServer(t)
|
||||
token := tserver.createSession(nick)
|
||||
|
||||
tserver.sendCommand(token, map[string]any{
|
||||
commandKey: irc.CmdPass,
|
||||
bodyKey: []string{testPassword},
|
||||
})
|
||||
tserver.setPassword(nick)
|
||||
|
||||
bytesToLimit := maxMessageSize - len(endpoint.value)
|
||||
|
||||
@@ -1763,9 +1765,7 @@ func checkQuitRace(
|
||||
firstToken := tserver.createSession(nick)
|
||||
observerToken := tserver.createSession("raceobserver")
|
||||
|
||||
tserver.sendCommand(firstToken, map[string]any{
|
||||
commandKey: irc.CmdPass, bodyKey: []string{testPassword},
|
||||
})
|
||||
tserver.setPassword(nick)
|
||||
|
||||
tokens := []string{firstToken, tserver.login(nick)}
|
||||
|
||||
@@ -1815,9 +1815,7 @@ func TestLogoutOfOneClientKeepsSession(t *testing.T) {
|
||||
firstToken := tserver.createSession(nick)
|
||||
observerToken := tserver.createSession("logoutobserver")
|
||||
|
||||
tserver.sendCommand(firstToken, map[string]any{
|
||||
commandKey: irc.CmdPass, bodyKey: []string{testPassword},
|
||||
})
|
||||
tserver.setPassword(nick)
|
||||
|
||||
secondToken := tserver.login(nick)
|
||||
|
||||
@@ -1887,15 +1885,12 @@ func TestFailedLogoutChangesNothing(t *testing.T) {
|
||||
|
||||
_, lastID := tserver.pollMessages(observerToken, 0)
|
||||
|
||||
_, err := tserver.database.GetDB().ExecContext(t.Context(),
|
||||
dbtest.Exec(t, tserver.dbURL,
|
||||
`CREATE TRIGGER keep_sessions
|
||||
BEFORE DELETE ON sessions
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'sessions are kept');
|
||||
END`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resp, err := doRequestAuth(
|
||||
t, http.MethodPost, tserver.url(apiLogout), token, nil,
|
||||
@@ -2129,6 +2124,24 @@ func (tserver *testServer) longPoll(
|
||||
return result.Messages, nil
|
||||
}
|
||||
|
||||
// setPassword gives the session nick the password testPassword
|
||||
// without sending PASS. It hashes at bcrypt.MinCost, and a login
|
||||
// compares at the cost stored in the hash, so both are fast.
|
||||
func (tserver *testServer) setPassword(nick string) {
|
||||
tserver.t.Helper()
|
||||
|
||||
hash, err := bcrypt.GenerateFromPassword(
|
||||
[]byte(testPassword), bcrypt.MinCost,
|
||||
)
|
||||
if err != nil {
|
||||
tserver.t.Fatalf("hash password: %v", err)
|
||||
}
|
||||
|
||||
dbtest.Exec(tserver.t, tserver.dbURL,
|
||||
"UPDATE sessions SET password_hash = '"+string(hash)+
|
||||
"' WHERE nick = '"+nick+"'")
|
||||
}
|
||||
|
||||
// login logs in to the session nick with testPassword and
|
||||
// returns the new client's token.
|
||||
func (tserver *testServer) login(nick string) string {
|
||||
@@ -3736,13 +3749,8 @@ func TestLoginValid(t *testing.T) {
|
||||
|
||||
tserver := newTestServer(t)
|
||||
|
||||
// Create session and set password via PASS command.
|
||||
token := tserver.createSession("loginuser")
|
||||
|
||||
tserver.sendCommand(token, map[string]any{
|
||||
commandKey: irc.CmdPass,
|
||||
bodyKey: []string{testPassword},
|
||||
})
|
||||
tserver.createSession("loginuser")
|
||||
tserver.setPassword("loginuser")
|
||||
|
||||
// Login with nick + password.
|
||||
loginBody, err := json.Marshal(map[string]string{
|
||||
@@ -3806,13 +3814,8 @@ func TestLoginWrongPassword(t *testing.T) {
|
||||
|
||||
tserver := newTestServer(t)
|
||||
|
||||
// Create session and set password via PASS command.
|
||||
token := tserver.createSession("wrongpwuser")
|
||||
|
||||
tserver.sendCommand(token, map[string]any{
|
||||
commandKey: irc.CmdPass,
|
||||
bodyKey: []string{"correctpass1"},
|
||||
})
|
||||
tserver.createSession("wrongpwuser")
|
||||
tserver.setPassword("wrongpwuser")
|
||||
|
||||
postJSONExpectStatus(
|
||||
t, tserver, "/api/v1/login",
|
||||
@@ -4283,13 +4286,8 @@ func TestLoginRateLimitAllowsNormalUse(t *testing.T) {
|
||||
|
||||
tserver := newTestServer(t)
|
||||
|
||||
// Create session and set password via PASS command.
|
||||
token := tserver.createSession("normaluser")
|
||||
|
||||
tserver.sendCommand(token, map[string]any{
|
||||
commandKey: irc.CmdPass,
|
||||
bodyKey: []string{testPassword},
|
||||
})
|
||||
tserver.createSession("normaluser")
|
||||
tserver.setPassword("normaluser")
|
||||
|
||||
// A single login should succeed without rate limiting.
|
||||
loginBody, err := json.Marshal(map[string]string{
|
||||
|
||||
Reference in New Issue
Block a user