test(whatsapp): add group trigger filtering tests
Covers the four cases introduced by the group_trigger fix: - mention_only: group message without mention is dropped - mention_only: group message with mentioned:true is forwarded - mention_only: group message with non-empty mentions array is forwarded - mention_only: DMs are always forwarded regardless of config - prefix: matching prefix is forwarded with prefix stripped - prefix: non-matching message is dropped - no config: permissive default forwards everything https://claude.ai/code/session_01PfpBofWnnVaNf7uyBEJA4T
This commit is contained in:
parent
ba57c99699
commit
55c15b8e29
1 changed files with 133 additions and 0 deletions
|
|
@ -9,6 +9,32 @@ import (
|
||||||
"github.com/sipeed/picoclaw/pkg/config"
|
"github.com/sipeed/picoclaw/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func newTestChannel(gt config.GroupTriggerConfig) (*WhatsAppChannel, *bus.MessageBus) {
|
||||||
|
messageBus := bus.NewMessageBus()
|
||||||
|
cfg := config.WhatsAppConfig{GroupTrigger: gt}
|
||||||
|
ch := &WhatsAppChannel{
|
||||||
|
BaseChannel: channels.NewBaseChannel("whatsapp", cfg, messageBus, nil,
|
||||||
|
channels.WithGroupTrigger(cfg.GroupTrigger),
|
||||||
|
),
|
||||||
|
ctx: context.Background(),
|
||||||
|
}
|
||||||
|
return ch, messageBus
|
||||||
|
}
|
||||||
|
|
||||||
|
// drainInbound returns the next non-observe-only message from the bus, if any.
|
||||||
|
// ObserveOnly messages (recorded by ObserveGroupMessage) are not counted as "forwarded".
|
||||||
|
func drainInbound(mb *bus.MessageBus) (bus.InboundMessage, bool) {
|
||||||
|
select {
|
||||||
|
case msg := <-mb.InboundChan():
|
||||||
|
if msg.ObserveOnly {
|
||||||
|
return bus.InboundMessage{}, false
|
||||||
|
}
|
||||||
|
return msg, true
|
||||||
|
default:
|
||||||
|
return bus.InboundMessage{}, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHandleIncomingMessage_DoesNotConsumeGenericCommandsLocally(t *testing.T) {
|
func TestHandleIncomingMessage_DoesNotConsumeGenericCommandsLocally(t *testing.T) {
|
||||||
messageBus := bus.NewMessageBus()
|
messageBus := bus.NewMessageBus()
|
||||||
ch := &WhatsAppChannel{
|
ch := &WhatsAppChannel{
|
||||||
|
|
@ -35,3 +61,110 @@ func TestHandleIncomingMessage_DoesNotConsumeGenericCommandsLocally(t *testing.T
|
||||||
t.Fatalf("content=%q", inbound.Content)
|
t.Fatalf("content=%q", inbound.Content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestGroupTrigger_MentionOnly verifies that with mention_only:true the bot
|
||||||
|
// ignores group messages unless the bridge signals a mention.
|
||||||
|
func TestGroupTrigger_MentionOnly(t *testing.T) {
|
||||||
|
gt := config.GroupTriggerConfig{MentionOnly: true}
|
||||||
|
|
||||||
|
t.Run("group message without mention is dropped", func(t *testing.T) {
|
||||||
|
ch, mb := newTestChannel(gt)
|
||||||
|
ch.handleIncomingMessage(map[string]any{
|
||||||
|
"from": "user1",
|
||||||
|
"chat": "group1",
|
||||||
|
"content": "hello everyone",
|
||||||
|
})
|
||||||
|
if _, ok := drainInbound(mb); ok {
|
||||||
|
t.Fatal("expected message to be dropped, but it was forwarded")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("group message with mentioned:true is forwarded", func(t *testing.T) {
|
||||||
|
ch, mb := newTestChannel(gt)
|
||||||
|
ch.handleIncomingMessage(map[string]any{
|
||||||
|
"from": "user1",
|
||||||
|
"chat": "group1",
|
||||||
|
"content": "hey bot",
|
||||||
|
"mentioned": true,
|
||||||
|
})
|
||||||
|
msg, ok := drainInbound(mb)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("expected message to be forwarded, but it was dropped")
|
||||||
|
}
|
||||||
|
if msg.Content != "hey bot" {
|
||||||
|
t.Fatalf("content=%q", msg.Content)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("group message with non-empty mentions array is forwarded", func(t *testing.T) {
|
||||||
|
ch, mb := newTestChannel(gt)
|
||||||
|
ch.handleIncomingMessage(map[string]any{
|
||||||
|
"from": "user1",
|
||||||
|
"chat": "group1",
|
||||||
|
"content": "hey bot",
|
||||||
|
"mentions": []any{"botjid@s.whatsapp.net"},
|
||||||
|
})
|
||||||
|
if _, ok := drainInbound(mb); !ok {
|
||||||
|
t.Fatal("expected message to be forwarded, but it was dropped")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("DM is always forwarded regardless of mention_only", func(t *testing.T) {
|
||||||
|
ch, mb := newTestChannel(gt)
|
||||||
|
ch.handleIncomingMessage(map[string]any{
|
||||||
|
"from": "user1",
|
||||||
|
"chat": "user1", // chat == sender → DM
|
||||||
|
"content": "private message",
|
||||||
|
})
|
||||||
|
if _, ok := drainInbound(mb); !ok {
|
||||||
|
t.Fatal("expected DM to be forwarded, but it was dropped")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGroupTrigger_Prefix verifies prefix-based group trigger filtering.
|
||||||
|
func TestGroupTrigger_Prefix(t *testing.T) {
|
||||||
|
gt := config.GroupTriggerConfig{Prefixes: []string{"/ask"}}
|
||||||
|
|
||||||
|
t.Run("group message with matching prefix is forwarded and prefix stripped", func(t *testing.T) {
|
||||||
|
ch, mb := newTestChannel(gt)
|
||||||
|
ch.handleIncomingMessage(map[string]any{
|
||||||
|
"from": "user1",
|
||||||
|
"chat": "group1",
|
||||||
|
"content": "/ask what time is it",
|
||||||
|
})
|
||||||
|
msg, ok := drainInbound(mb)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("expected message to be forwarded")
|
||||||
|
}
|
||||||
|
if msg.Content != "what time is it" {
|
||||||
|
t.Fatalf("content=%q, want %q", msg.Content, "what time is it")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("group message without prefix is dropped", func(t *testing.T) {
|
||||||
|
ch, mb := newTestChannel(gt)
|
||||||
|
ch.handleIncomingMessage(map[string]any{
|
||||||
|
"from": "user1",
|
||||||
|
"chat": "group1",
|
||||||
|
"content": "hello",
|
||||||
|
})
|
||||||
|
if _, ok := drainInbound(mb); ok {
|
||||||
|
t.Fatal("expected message to be dropped")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGroupTrigger_NoConfig verifies that without any group_trigger config the
|
||||||
|
// bot responds to all group messages (permissive default).
|
||||||
|
func TestGroupTrigger_NoConfig(t *testing.T) {
|
||||||
|
ch, mb := newTestChannel(config.GroupTriggerConfig{})
|
||||||
|
ch.handleIncomingMessage(map[string]any{
|
||||||
|
"from": "user1",
|
||||||
|
"chat": "group1",
|
||||||
|
"content": "any message",
|
||||||
|
})
|
||||||
|
if _, ok := drainInbound(mb); !ok {
|
||||||
|
t.Fatal("expected message to be forwarded with no group_trigger config")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue