Stop the slow test packages waiting (closes #263)
check / check (push) Failing after 7s

- Tests hash passwords at bcrypt.MinCost through db.PasswordCost.
- Test IRC servers check the queue only on broker notification;
  one test keeps the 100 ms fallback poll.
- The stop-timeout test shortens the timeout through a test-only
  setter.
- service and handlers tests build config.Config directly instead
  of through config.New, so they run in parallel: service had run
  serially, and handlers started its servers one at a time.
- Repeated race trials run as parallel subtests.
- Fixed sleeps become waits on the broker.
- A new test covers the relay's failed queue read, which only the
  100 ms poll had reached.

Model: opus-5-5
This commit is contained in:
sneak committed 2026-11-10 20:37:33 +00:00
1 parent bc8aa6bb96
commit c492e5969e
11 files changed
+356 -198

No files matched your search

+129 -89
View File
@@ -1,7 +1,3 @@
// Tests use a global viper instance for configuration,
// making parallel execution unsafe.
//
//nolint:paralleltest
package service_test
import (
@@ -59,28 +55,12 @@ func newTestEnv(t *testing.T) *testEnv {
}
},
logger.New,
func(
lifecycle fx.Lifecycle,
globs *globals.Globals,
log *logger.Logger,
) (*config.Config, error) {
cfg, err := config.New(
lifecycle, config.Params{ //nolint:exhaustruct
Globals: globs, Logger: log,
},
)
if err != nil {
return nil, fmt.Errorf(
"test config: %w", err,
)
func() *config.Config {
return &config.Config{
DBURL: dbURL,
OperName: "admin",
OperPassword: "secret",
}
cfg.DBURL = dbURL
cfg.Port = 0
cfg.OperName = "admin"
cfg.OperPassword = "secret"
return cfg, nil
},
func(
lifecycle fx.Lifecycle,
@@ -136,6 +116,8 @@ func createSession(
// environment starts on an empty database while another one
// is still open.
func TestEachTestEnvHasItsOwnDatabase(t *testing.T) {
t.Parallel()
ctx := t.Context()
first := newTestEnv(t)
@@ -146,6 +128,8 @@ func TestEachTestEnvHasItsOwnDatabase(t *testing.T) {
}
func TestFanOut(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -173,6 +157,8 @@ func TestFanOut(t *testing.T) {
}
func TestJoinChannel(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -213,6 +199,8 @@ func TestJoinChannel(t *testing.T) {
}
func TestPartChannel(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -313,6 +301,8 @@ func joinConcurrently(
// concurrent JOINs of a +l 2 channel with one member, one
// gets in and the other gets ERR_CHANNELISFULL.
func TestConcurrentJoinsRespectUserLimit(t *testing.T) {
t.Parallel()
const userLimit = 2
env := newTestEnv(t)
@@ -375,6 +365,8 @@ func TestConcurrentJoinsRespectUserLimit(t *testing.T) {
// two concurrent JOINs that create a channel, exactly one
// makes its session the operator.
func TestConcurrentFirstJoinsMakeOneOperator(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -426,6 +418,8 @@ func TestConcurrentFirstJoinsMakeOneOperator(t *testing.T) {
// either joins a channel that still exists or gets
// ERR_NOSUCHCHANNEL, and never fails otherwise.
func TestJoinConcurrentWithLastPart(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -491,6 +485,8 @@ func TestJoinConcurrentWithLastPart(t *testing.T) {
// quits, gets in only once the channel is deleted, into a
// new channel of that name with no key.
func TestJoinConcurrentWithLastQuit(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -569,81 +565,95 @@ const quitCrowdSize = 10
// ahead of that JOIN. The quitting session is also on a
// channel with quitCrowdSize other sessions, made before the
// watcher's channel, so that its QUIT reaches the watcher
// last.
// last. Each trial runs on a database of its own.
func TestQuitQueuedAheadOfNewNickHoldersJoin(t *testing.T) {
env := newTestEnv(t)
ctx := t.Context()
t.Parallel()
for trial := range concurrentJoinTrials {
nick := fmt.Sprintf("reused%d", trial)
crowd := fmt.Sprintf("#crowd%d", trial)
shared := fmt.Sprintf("#shared%d", trial)
quitterSID := createSession(ctx, t, env.db, nick)
t.Run(fmt.Sprintf("trial %d", trial), func(t *testing.T) {
t.Parallel()
for _, channel := range []string{crowd, shared} {
_, err := env.svc.JoinChannel(ctx, quitterSID, 0, nick, channel, "")
if err != nil {
t.Fatalf("join %s: %v", channel, err)
}
checkQuitQueuedAheadOfJoin(t, newTestEnv(t))
})
}
}
// checkQuitQueuedAheadOfJoin runs one trial of
// TestQuitQueuedAheadOfNewNickHoldersJoin on env.
func checkQuitQueuedAheadOfJoin(t *testing.T, env *testEnv) {
t.Helper()
const (
nick = "reused"
crowd = "#crowd"
shared = "#shared"
watcherNick = "watcher"
)
ctx := t.Context()
quitterSID := createSession(ctx, t, env.db, nick)
for _, channel := range []string{crowd, shared} {
_, err := env.svc.JoinChannel(ctx, quitterSID, 0, nick, channel, "")
if err != nil {
t.Fatalf("join %s: %v", channel, err)
}
}
for member := range quitCrowdSize {
memberNick := fmt.Sprintf("crowd%dx%d", trial, member)
memberSID := createSession(ctx, t, env.db, memberNick)
for member := range quitCrowdSize {
memberNick := fmt.Sprintf("crowd%d", member)
memberSID := createSession(ctx, t, env.db, memberNick)
_, err := env.svc.JoinChannel(ctx, memberSID, 0, memberNick, crowd, "")
if err != nil {
t.Fatalf("join %s: %v", memberNick, err)
}
_, err := env.svc.JoinChannel(ctx, memberSID, 0, memberNick, crowd, "")
if err != nil {
t.Fatalf("join %s: %v", memberNick, err)
}
}
watcherNick := fmt.Sprintf("watcher%d", trial)
watcherSID, watcherClientID, _, err := env.db.CreateSession(
ctx, watcherNick, watcherNick, "localhost", "127.0.0.1",
)
if err != nil {
t.Fatalf("create session %s: %v", watcherNick, err)
}
watcherSID, watcherClientID, _, err := env.db.CreateSession(
ctx, watcherNick, watcherNick, "localhost", "127.0.0.1",
_, err = env.svc.JoinChannel(ctx, watcherSID, 0, watcherNick, shared, "")
if err != nil {
t.Fatalf("join %s: %v", watcherNick, err)
}
_, lastQueueID, err := env.db.PollMessages(ctx, watcherClientID, 0, 0)
if err != nil {
t.Fatalf("poll: %v", err)
}
errs := runConcurrently(
func() error {
env.svc.BroadcastQuit(ctx, quitterSID, nick, "")
return nil
},
func() error {
return takeNickAndJoin(ctx, env, nick, shared)
},
)
if errs[1] != nil {
t.Fatalf("new session: %v", errs[1])
}
msgs, _, err := env.db.PollMessages(
ctx, watcherClientID, lastQueueID, 0,
)
if err != nil {
t.Fatalf("poll: %v", err)
}
commands := commandsFrom(msgs, nick)
if !slices.Equal(commands, []string{irc.CmdQuit, irc.CmdJoin}) {
t.Errorf(
"watcher got %v from %s, want QUIT then JOIN",
commands, nick,
)
if err != nil {
t.Fatalf("create session %s: %v", watcherNick, err)
}
_, err = env.svc.JoinChannel(ctx, watcherSID, 0, watcherNick, shared, "")
if err != nil {
t.Fatalf("join %s: %v", watcherNick, err)
}
_, lastQueueID, err := env.db.PollMessages(ctx, watcherClientID, 0, 0)
if err != nil {
t.Fatalf("poll: %v", err)
}
errs := runConcurrently(
func() error {
env.svc.BroadcastQuit(ctx, quitterSID, nick, "")
return nil
},
func() error {
return takeNickAndJoin(ctx, env, nick, shared)
},
)
if errs[1] != nil {
t.Fatalf("trial %d: new session: %v", trial, errs[1])
}
msgs, _, err := env.db.PollMessages(
ctx, watcherClientID, lastQueueID, 0,
)
if err != nil {
t.Fatalf("poll: %v", err)
}
commands := commandsFrom(msgs, nick)
if !slices.Equal(commands, []string{irc.CmdQuit, irc.CmdJoin}) {
t.Errorf(
"trial %d: watcher got %v from %s, want QUIT then JOIN",
trial, commands, nick,
)
}
}
}
@@ -691,6 +701,8 @@ func commandsFrom(msgs []db.IRCMessage, nick string) []string {
// into a +i channel uses the invite up, so that a JOIN
// after leaving gets ERR_INVITEONLYCHAN.
func TestJoinUsesUpInvite(t *testing.T) {
t.Parallel()
const channel = "#club"
env := newTestEnv(t)
@@ -736,6 +748,8 @@ func TestJoinUsesUpInvite(t *testing.T) {
// session's nick, username and hostname refuses its JOIN
// with ERR_BANNEDFROMCHAN.
func TestJoinRefusedByHostmaskBan(t *testing.T) {
t.Parallel()
const channel = "#club"
env := newTestEnv(t)
@@ -774,6 +788,8 @@ func TestJoinRefusedByHostmaskBan(t *testing.T) {
// keeps a channel other members are still on and deletes
// the channel when its last member parts.
func TestPartDeletesChannelOnlyWhenEmpty(t *testing.T) {
t.Parallel()
const channel = "#room"
env := newTestEnv(t)
@@ -821,6 +837,8 @@ func TestPartDeletesChannelOnlyWhenEmpty(t *testing.T) {
// TestKickOfLastMemberDeletesChannel checks that a KICK
// that leaves a channel with no members deletes it.
func TestKickOfLastMemberDeletesChannel(t *testing.T) {
t.Parallel()
const channel = "#room"
env := newTestEnv(t)
@@ -845,6 +863,8 @@ func TestKickOfLastMemberDeletesChannel(t *testing.T) {
}
func TestSendChannelMessage(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -892,6 +912,8 @@ func TestSendChannelMessage(t *testing.T) {
}
func TestBroadcastQuit(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -929,6 +951,8 @@ func TestBroadcastQuit(t *testing.T) {
// error as a DM to an unknown nick. The trigger deletes the
// target's session just before the DM is stored.
func TestSendDirectMessageTargetQuits(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -960,6 +984,8 @@ func TestSendDirectMessageTargetQuits(t *testing.T) {
// trigger deletes the channel just before the message is
// stored.
func TestSendChannelMessageChannelDeleted(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -991,6 +1017,8 @@ func TestSendChannelMessageChannelDeleted(t *testing.T) {
}
func TestSendChannelMessage_Moderated(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -1042,6 +1070,8 @@ func TestSendChannelMessage_Moderated(t *testing.T) {
// not spend its hashcash stamp: the operator can then send
// the same message with it.
func TestRefusedChannelMessageLeavesStampUnspent(t *testing.T) {
t.Parallel()
const (
channel = "#paid"
bits = 2
@@ -1067,6 +1097,8 @@ func TestRefusedChannelMessageLeavesStampUnspent(t *testing.T) {
for _, refusal := range refusals {
t.Run(refusal.name, func(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -1119,6 +1151,8 @@ func TestRefusedChannelMessageLeavesStampUnspent(t *testing.T) {
}
func TestQueryUserMode(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -1169,6 +1203,8 @@ func TestQueryUserMode(t *testing.T) {
}
func TestUserhostReply(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
ctx := t.Context()
@@ -1274,10 +1310,14 @@ func applyUserModeTests() []applyUserModeTest {
}
func TestApplyUserMode(t *testing.T) {
t.Parallel()
env := newTestEnv(t)
for i, test := range applyUserModeTests() {
t.Run(test.modeStr, func(t *testing.T) {
t.Parallel()
ctx := t.Context()
sid := createSession(
ctx, t, env.db, fmt.Sprintf("user%d", i),