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 that need a password only to log in store one hashed at bcrypt.MinCost. Tests of PASS itself keep the real cost. Model: opus-5-5
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