Show an IRC listener user what their session sends from other clients (closes #179)
check / check (push) Waiting to run
check / check (push) Waiting to run
The IRC listener's relay dropped every line sent under the connection's own nick, so a user on the web client and an IRC client at once never saw on IRC what they did from the web client. The relay now drops nothing by nick. Instead the fan-out skips only the sending client's own queue: the IRC listener passes its own client, whose handler already wrote the echo, and the HTTP API skips none. Channel messages and PARTs now reach the sender's other clients, so an HTTP client gets its own PART event; neoirc-cli ignores it, as it already shows its own part. README.md names the commands covered. Judgement call: a PRIVMSG or NOTICE sent on an IRC connection is not echoed back to it, as in IRC. Model: opus-5-5
This commit was merged in pull request #183.
This commit is contained in:
@@ -168,7 +168,7 @@ func TestFanOut(t *testing.T) {
|
||||
dbID, uuid, err := env.svc.FanOut(
|
||||
ctx, irc.CmdPrivmsg, "alice", "#test", 0, 0,
|
||||
nil, body, nil,
|
||||
[]int64{sid1, sid2},
|
||||
[]int64{sid1, sid2}, 0,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("FanOut: %v", err)
|
||||
@@ -190,7 +190,7 @@ func TestJoinChannel(t *testing.T) {
|
||||
sid := createSession(ctx, t, env.db, "alice")
|
||||
|
||||
result, err := env.svc.JoinChannel(
|
||||
ctx, sid, "alice", "#general", "",
|
||||
ctx, sid, 0, "alice", "#general", "",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("JoinChannel: %v", err)
|
||||
@@ -208,7 +208,7 @@ func TestJoinChannel(t *testing.T) {
|
||||
sid2 := createSession(ctx, t, env.db, "bob")
|
||||
|
||||
result2, err := env.svc.JoinChannel(
|
||||
ctx, sid2, "bob", "#general", "",
|
||||
ctx, sid2, 0, "bob", "#general", "",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("JoinChannel bob: %v", err)
|
||||
@@ -230,14 +230,14 @@ func TestPartChannel(t *testing.T) {
|
||||
sid := createSession(ctx, t, env.db, "alice")
|
||||
|
||||
_, err := env.svc.JoinChannel(
|
||||
ctx, sid, "alice", "#general", "",
|
||||
ctx, sid, 0, "alice", "#general", "",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("JoinChannel: %v", err)
|
||||
}
|
||||
|
||||
err = env.svc.PartChannel(
|
||||
ctx, sid, "alice", "#general", "bye",
|
||||
ctx, sid, 0, "alice", "#general", "bye",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("PartChannel: %v", err)
|
||||
@@ -245,7 +245,7 @@ func TestPartChannel(t *testing.T) {
|
||||
|
||||
// Parting a non-existent channel returns error.
|
||||
err = env.svc.PartChannel(
|
||||
ctx, sid, "alice", "#nonexistent", "",
|
||||
ctx, sid, 0, "alice", "#nonexistent", "",
|
||||
)
|
||||
if err == nil {
|
||||
t.Error("expected error for non-existent channel")
|
||||
@@ -309,7 +309,7 @@ func joinConcurrently(
|
||||
|
||||
joins[i] = func() error {
|
||||
result, err := env.svc.JoinChannel(
|
||||
ctx, sessionID, nick, channel, "",
|
||||
ctx, sessionID, 0, nick, channel, "",
|
||||
)
|
||||
results[i] = result
|
||||
|
||||
@@ -335,7 +335,7 @@ func TestConcurrentJoinsRespectUserLimit(t *testing.T) {
|
||||
opSID := createSession(ctx, t, env.db, opNick)
|
||||
|
||||
created, err := env.svc.JoinChannel(
|
||||
ctx, opSID, opNick, channel, "",
|
||||
ctx, opSID, 0, opNick, channel, "",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("join %s: %v", opNick, err)
|
||||
@@ -448,7 +448,7 @@ func TestJoinConcurrentWithLastPart(t *testing.T) {
|
||||
joinerSID := createSession(ctx, t, env.db, joinerNick)
|
||||
|
||||
_, err := env.svc.JoinChannel(
|
||||
ctx, leaverSID, leaverNick, channel, "",
|
||||
ctx, leaverSID, 0, leaverNick, channel, "",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("join %s: %v", leaverNick, err)
|
||||
@@ -457,12 +457,12 @@ func TestJoinConcurrentWithLastPart(t *testing.T) {
|
||||
errs := runConcurrently(
|
||||
func() error {
|
||||
return env.svc.PartChannel(
|
||||
ctx, leaverSID, leaverNick, channel, "",
|
||||
ctx, leaverSID, 0, leaverNick, channel, "",
|
||||
)
|
||||
},
|
||||
func() error {
|
||||
_, joinErr := env.svc.JoinChannel(
|
||||
ctx, joinerSID, joinerNick, channel, "",
|
||||
ctx, joinerSID, 0, joinerNick, channel, "",
|
||||
)
|
||||
|
||||
return joinErr
|
||||
@@ -513,7 +513,7 @@ func TestJoinConcurrentWithLastQuit(t *testing.T) {
|
||||
joinerSID := createSession(ctx, t, env.db, joinerNick)
|
||||
|
||||
created, err := env.svc.JoinChannel(
|
||||
ctx, leaverSID, leaverNick, channel, "",
|
||||
ctx, leaverSID, 0, leaverNick, channel, "",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("join %s: %v", leaverNick, err)
|
||||
@@ -545,7 +545,7 @@ func TestJoinConcurrentWithLastQuit(t *testing.T) {
|
||||
)
|
||||
|
||||
joined, joinErr = env.svc.JoinChannel(
|
||||
ctx, joinerSID, joinerNick, channel, "",
|
||||
ctx, joinerSID, 0, joinerNick, channel, "",
|
||||
)
|
||||
if !errors.As(joinErr, &ircErr) ||
|
||||
ircErr.Code != irc.ErrBadChannelKey {
|
||||
@@ -592,7 +592,7 @@ func TestQuitQueuedAheadOfNewNickHoldersJoin(t *testing.T) {
|
||||
quitterSID := createSession(ctx, t, env.db, nick)
|
||||
|
||||
for _, channel := range []string{crowd, shared} {
|
||||
_, err := env.svc.JoinChannel(ctx, quitterSID, nick, channel, "")
|
||||
_, err := env.svc.JoinChannel(ctx, quitterSID, 0, nick, channel, "")
|
||||
if err != nil {
|
||||
t.Fatalf("join %s: %v", channel, err)
|
||||
}
|
||||
@@ -602,7 +602,7 @@ func TestQuitQueuedAheadOfNewNickHoldersJoin(t *testing.T) {
|
||||
memberNick := fmt.Sprintf("crowd%dx%d", trial, member)
|
||||
memberSID := createSession(ctx, t, env.db, memberNick)
|
||||
|
||||
_, err := env.svc.JoinChannel(ctx, memberSID, memberNick, crowd, "")
|
||||
_, err := env.svc.JoinChannel(ctx, memberSID, 0, memberNick, crowd, "")
|
||||
if err != nil {
|
||||
t.Fatalf("join %s: %v", memberNick, err)
|
||||
}
|
||||
@@ -617,7 +617,7 @@ func TestQuitQueuedAheadOfNewNickHoldersJoin(t *testing.T) {
|
||||
t.Fatalf("create session %s: %v", watcherNick, err)
|
||||
}
|
||||
|
||||
_, err = env.svc.JoinChannel(ctx, watcherSID, watcherNick, shared, "")
|
||||
_, err = env.svc.JoinChannel(ctx, watcherSID, 0, watcherNick, shared, "")
|
||||
if err != nil {
|
||||
t.Fatalf("join %s: %v", watcherNick, err)
|
||||
}
|
||||
@@ -678,7 +678,7 @@ func takeNickAndJoin(
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = env.svc.JoinChannel(ctx, sessionID, nick, channel, "")
|
||||
_, err = env.svc.JoinChannel(ctx, sessionID, 0, nick, channel, "")
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -710,7 +710,7 @@ func TestJoinUsesUpInvite(t *testing.T) {
|
||||
opSID := createSession(ctx, t, env.db, "op")
|
||||
guestSID := createSession(ctx, t, env.db, "guest")
|
||||
|
||||
created, err := env.svc.JoinChannel(ctx, opSID, "op", channel, "")
|
||||
created, err := env.svc.JoinChannel(ctx, opSID, 0, "op", channel, "")
|
||||
if err != nil {
|
||||
t.Fatalf("join op: %v", err)
|
||||
}
|
||||
@@ -725,17 +725,17 @@ func TestJoinUsesUpInvite(t *testing.T) {
|
||||
t.Fatalf("invite guest: %v", err)
|
||||
}
|
||||
|
||||
_, err = env.svc.JoinChannel(ctx, guestSID, "guest", channel, "")
|
||||
_, err = env.svc.JoinChannel(ctx, guestSID, 0, "guest", channel, "")
|
||||
if err != nil {
|
||||
t.Fatalf("invited join: %v", err)
|
||||
}
|
||||
|
||||
err = env.svc.PartChannel(ctx, guestSID, "guest", channel, "")
|
||||
err = env.svc.PartChannel(ctx, guestSID, 0, "guest", channel, "")
|
||||
if err != nil {
|
||||
t.Fatalf("part guest: %v", err)
|
||||
}
|
||||
|
||||
_, err = env.svc.JoinChannel(ctx, guestSID, "guest", channel, "")
|
||||
_, err = env.svc.JoinChannel(ctx, guestSID, 0, "guest", channel, "")
|
||||
|
||||
var ircErr *service.IRCError
|
||||
if !errors.As(err, &ircErr) || ircErr.Code != irc.ErrInviteOnlyChan {
|
||||
@@ -754,7 +754,7 @@ func TestJoinRefusedByHostmaskBan(t *testing.T) {
|
||||
|
||||
opSID := createSession(ctx, t, env.db, "op")
|
||||
|
||||
created, err := env.svc.JoinChannel(ctx, opSID, "op", channel, "")
|
||||
created, err := env.svc.JoinChannel(ctx, opSID, 0, "op", channel, "")
|
||||
if err != nil {
|
||||
t.Fatalf("join op: %v", err)
|
||||
}
|
||||
@@ -773,7 +773,7 @@ func TestJoinRefusedByHostmaskBan(t *testing.T) {
|
||||
t.Fatalf("create session guest: %v", err)
|
||||
}
|
||||
|
||||
_, err = env.svc.JoinChannel(ctx, guestSID, "guest", channel, "")
|
||||
_, err = env.svc.JoinChannel(ctx, guestSID, 0, "guest", channel, "")
|
||||
|
||||
var ircErr *service.IRCError
|
||||
if !errors.As(err, &ircErr) || ircErr.Code != irc.ErrBannedFromChan {
|
||||
@@ -793,17 +793,17 @@ func TestPartDeletesChannelOnlyWhenEmpty(t *testing.T) {
|
||||
aliceSID := createSession(ctx, t, env.db, "alice")
|
||||
bobSID := createSession(ctx, t, env.db, "bob")
|
||||
|
||||
_, err := env.svc.JoinChannel(ctx, aliceSID, "alice", channel, "")
|
||||
_, err := env.svc.JoinChannel(ctx, aliceSID, 0, "alice", channel, "")
|
||||
if err != nil {
|
||||
t.Fatalf("join alice: %v", err)
|
||||
}
|
||||
|
||||
_, err = env.svc.JoinChannel(ctx, bobSID, "bob", channel, "")
|
||||
_, err = env.svc.JoinChannel(ctx, bobSID, 0, "bob", channel, "")
|
||||
if err != nil {
|
||||
t.Fatalf("join bob: %v", err)
|
||||
}
|
||||
|
||||
err = env.svc.PartChannel(ctx, aliceSID, "alice", channel, "")
|
||||
err = env.svc.PartChannel(ctx, aliceSID, 0, "alice", channel, "")
|
||||
if err != nil {
|
||||
t.Fatalf("part alice: %v", err)
|
||||
}
|
||||
@@ -818,7 +818,7 @@ func TestPartDeletesChannelOnlyWhenEmpty(t *testing.T) {
|
||||
t.Fatal("bob is not on the channel after alice parted")
|
||||
}
|
||||
|
||||
err = env.svc.PartChannel(ctx, bobSID, "bob", channel, "")
|
||||
err = env.svc.PartChannel(ctx, bobSID, 0, "bob", channel, "")
|
||||
if err != nil {
|
||||
t.Fatalf("part bob: %v", err)
|
||||
}
|
||||
@@ -839,12 +839,12 @@ func TestKickOfLastMemberDeletesChannel(t *testing.T) {
|
||||
|
||||
sid := createSession(ctx, t, env.db, "alice")
|
||||
|
||||
_, err := env.svc.JoinChannel(ctx, sid, "alice", channel, "")
|
||||
_, err := env.svc.JoinChannel(ctx, sid, 0, "alice", channel, "")
|
||||
if err != nil {
|
||||
t.Fatalf("join alice: %v", err)
|
||||
}
|
||||
|
||||
err = env.svc.KickUser(ctx, sid, "alice", channel, "alice", "")
|
||||
err = env.svc.KickUser(ctx, sid, 0, "alice", channel, "alice", "")
|
||||
if err != nil {
|
||||
t.Fatalf("kick alice: %v", err)
|
||||
}
|
||||
@@ -863,14 +863,14 @@ func TestSendChannelMessage(t *testing.T) {
|
||||
sid2 := createSession(ctx, t, env.db, "bob")
|
||||
|
||||
_, err := env.svc.JoinChannel(
|
||||
ctx, sid1, "alice", "#chat", "",
|
||||
ctx, sid1, 0, "alice", "#chat", "",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("join alice: %v", err)
|
||||
}
|
||||
|
||||
_, err = env.svc.JoinChannel(
|
||||
ctx, sid2, "bob", "#chat", "",
|
||||
ctx, sid2, 0, "bob", "#chat", "",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("join bob: %v", err)
|
||||
@@ -878,18 +878,14 @@ func TestSendChannelMessage(t *testing.T) {
|
||||
|
||||
body, _ := json.Marshal([]string{"hello world"}) //nolint:errchkjson
|
||||
|
||||
dbID, uuid, err := env.svc.SendChannelMessage(
|
||||
ctx, sid1, "alice",
|
||||
uuid, err := env.svc.SendChannelMessage(
|
||||
ctx, sid1, 0, "alice",
|
||||
irc.CmdPrivmsg, "#chat", body, nil,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("SendChannelMessage: %v", err)
|
||||
}
|
||||
|
||||
if dbID == 0 {
|
||||
t.Error("expected non-zero dbID")
|
||||
}
|
||||
|
||||
if uuid == "" {
|
||||
t.Error("expected non-empty UUID")
|
||||
}
|
||||
@@ -897,8 +893,8 @@ func TestSendChannelMessage(t *testing.T) {
|
||||
// Non-member cannot send.
|
||||
sid3 := createSession(ctx, t, env.db, "charlie")
|
||||
|
||||
_, _, err = env.svc.SendChannelMessage(
|
||||
ctx, sid3, "charlie",
|
||||
_, err = env.svc.SendChannelMessage(
|
||||
ctx, sid3, 0, "charlie",
|
||||
irc.CmdPrivmsg, "#chat", body, nil,
|
||||
)
|
||||
if err == nil {
|
||||
@@ -914,14 +910,14 @@ func TestBroadcastQuit(t *testing.T) {
|
||||
sid2 := createSession(ctx, t, env.db, "bob")
|
||||
|
||||
_, err := env.svc.JoinChannel(
|
||||
ctx, sid1, "alice", "#room", "",
|
||||
ctx, sid1, 0, "alice", "#room", "",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("join alice: %v", err)
|
||||
}
|
||||
|
||||
_, err = env.svc.JoinChannel(
|
||||
ctx, sid2, "bob", "#room", "",
|
||||
ctx, sid2, 0, "bob", "#room", "",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("join bob: %v", err)
|
||||
@@ -963,7 +959,7 @@ func TestSendDirectMessageTargetQuits(t *testing.T) {
|
||||
body, _ := json.Marshal([]string{"hi"}) //nolint:errchkjson
|
||||
|
||||
_, err = env.svc.SendDirectMessage(
|
||||
ctx, sid, "alice", irc.CmdPrivmsg, "bob", body, nil,
|
||||
ctx, sid, 0, "alice", irc.CmdPrivmsg, "bob", body, nil,
|
||||
)
|
||||
|
||||
var ircErr *service.IRCError
|
||||
@@ -983,7 +979,7 @@ func TestSendChannelMessageChannelDeleted(t *testing.T) {
|
||||
|
||||
sid := createSession(ctx, t, env.db, "alice")
|
||||
|
||||
_, err := env.svc.JoinChannel(ctx, sid, "alice", "#gone", "")
|
||||
_, err := env.svc.JoinChannel(ctx, sid, 0, "alice", "#gone", "")
|
||||
if err != nil {
|
||||
t.Fatalf("join alice: %v", err)
|
||||
}
|
||||
@@ -1000,8 +996,8 @@ func TestSendChannelMessageChannelDeleted(t *testing.T) {
|
||||
|
||||
body, _ := json.Marshal([]string{"hi"}) //nolint:errchkjson
|
||||
|
||||
_, _, err = env.svc.SendChannelMessage(
|
||||
ctx, sid, "alice", irc.CmdPrivmsg, "#gone", body, nil,
|
||||
_, err = env.svc.SendChannelMessage(
|
||||
ctx, sid, 0, "alice", irc.CmdPrivmsg, "#gone", body, nil,
|
||||
)
|
||||
|
||||
var ircErr *service.IRCError
|
||||
@@ -1019,14 +1015,14 @@ func TestSendChannelMessage_Moderated(t *testing.T) {
|
||||
sid2 := createSession(ctx, t, env.db, "bob")
|
||||
|
||||
result, err := env.svc.JoinChannel(
|
||||
ctx, sid1, "alice", "#modchat", "",
|
||||
ctx, sid1, 0, "alice", "#modchat", "",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("join alice: %v", err)
|
||||
}
|
||||
|
||||
_, err = env.svc.JoinChannel(
|
||||
ctx, sid2, "bob", "#modchat", "",
|
||||
ctx, sid2, 0, "bob", "#modchat", "",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("join bob: %v", err)
|
||||
@@ -1039,8 +1035,8 @@ func TestSendChannelMessage_Moderated(t *testing.T) {
|
||||
body, _ := json.Marshal([]string{"test"}) //nolint:errchkjson
|
||||
|
||||
// Bob (non-op, non-voiced) should fail to send.
|
||||
_, _, err = env.svc.SendChannelMessage(
|
||||
ctx, sid2, "bob",
|
||||
_, err = env.svc.SendChannelMessage(
|
||||
ctx, sid2, 0, "bob",
|
||||
irc.CmdPrivmsg, "#modchat", body, nil,
|
||||
)
|
||||
if err == nil {
|
||||
@@ -1048,8 +1044,8 @@ func TestSendChannelMessage_Moderated(t *testing.T) {
|
||||
}
|
||||
|
||||
// Alice (operator) should succeed.
|
||||
_, _, err = env.svc.SendChannelMessage(
|
||||
ctx, sid1, "alice",
|
||||
_, err = env.svc.SendChannelMessage(
|
||||
ctx, sid1, 0, "alice",
|
||||
irc.CmdPrivmsg, "#modchat", body, nil,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -1074,7 +1070,7 @@ func TestRefusedChannelMessageLeavesStampUnspent(t *testing.T) {
|
||||
refuse func(ctx context.Context, env *testEnv, chID, bobSID int64) error
|
||||
}{
|
||||
{"not a member", func(ctx context.Context, env *testEnv, _, bobSID int64) error {
|
||||
return env.svc.PartChannel(ctx, bobSID, "bob", channel, "")
|
||||
return env.svc.PartChannel(ctx, bobSID, 0, "bob", channel, "")
|
||||
}},
|
||||
{"banned", func(ctx context.Context, env *testEnv, chID, _ int64) error {
|
||||
return env.db.AddChannelBan(ctx, chID, "bob!*@*", "alice")
|
||||
@@ -1094,12 +1090,12 @@ func TestRefusedChannelMessageLeavesStampUnspent(t *testing.T) {
|
||||
aliceSID := createSession(ctx, t, env.db, "alice")
|
||||
bobSID := createSession(ctx, t, env.db, "bob")
|
||||
|
||||
joined, err := env.svc.JoinChannel(ctx, aliceSID, "alice", channel, "")
|
||||
joined, err := env.svc.JoinChannel(ctx, aliceSID, 0, "alice", channel, "")
|
||||
if err != nil {
|
||||
t.Fatalf("join alice: %v", err)
|
||||
}
|
||||
|
||||
_, err = env.svc.JoinChannel(ctx, bobSID, "bob", channel, "")
|
||||
_, err = env.svc.JoinChannel(ctx, bobSID, 0, "bob", channel, "")
|
||||
if err != nil {
|
||||
t.Fatalf("join bob: %v", err)
|
||||
}
|
||||
@@ -1119,8 +1115,8 @@ func TestRefusedChannelMessageLeavesStampUnspent(t *testing.T) {
|
||||
)
|
||||
meta, _ := json.Marshal(map[string]string{"hashcash": stamp})
|
||||
|
||||
_, _, err = env.svc.SendChannelMessage(
|
||||
ctx, bobSID, "bob", irc.CmdPrivmsg, channel, body, meta,
|
||||
_, err = env.svc.SendChannelMessage(
|
||||
ctx, bobSID, 0, "bob", irc.CmdPrivmsg, channel, body, meta,
|
||||
)
|
||||
|
||||
var ircErr *service.IRCError
|
||||
@@ -1129,8 +1125,8 @@ func TestRefusedChannelMessageLeavesStampUnspent(t *testing.T) {
|
||||
t.Fatalf("bob: want ERR_CANNOTSENDTOCHAN, got %v", err)
|
||||
}
|
||||
|
||||
_, _, err = env.svc.SendChannelMessage(
|
||||
ctx, aliceSID, "alice", irc.CmdPrivmsg, channel, body, meta,
|
||||
_, err = env.svc.SendChannelMessage(
|
||||
ctx, aliceSID, 0, "alice", irc.CmdPrivmsg, channel, body, meta,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("alice with the same stamp: %v", err)
|
||||
|
||||
Reference in New Issue
Block a user