]> git.giacomolli.uk - onechat/blobdiff - whatsapp_test.go
Give the WhatsApp batches to the agent
[onechat] / whatsapp_test.go
index e0018e5ba2a744d99f6130ed03b269dd366ebfc1..38a7b8d765576a8294db3e5376f9d8af2026a18a 100644 (file)
@@ -2,6 +2,7 @@ package main
 
 import (
        "errors"
 
 import (
        "errors"
+       "net/http"
        "os"
        "path/filepath"
        "strings"
        "os"
        "path/filepath"
        "strings"
@@ -10,6 +11,8 @@ import (
 
        "github.com/stretchr/testify/require"
        "go.mau.fi/whatsmeow"
 
        "github.com/stretchr/testify/require"
        "go.mau.fi/whatsmeow"
+       "go.mau.fi/whatsmeow/proto/waE2E"
+       "go.mau.fi/whatsmeow/proto/waWeb"
        "go.mau.fi/whatsmeow/types"
        "go.mau.fi/whatsmeow/types/events"
 )
        "go.mau.fi/whatsmeow/types"
        "go.mau.fi/whatsmeow/types/events"
 )
@@ -467,3 +470,203 @@ func whatsappTestLogTexts(t *testing.T, memory *Memory) []string {
 
        return texts
 }
 
        return texts
 }
+
+func TestWhatsAppPrivateBatchStartsATurnWithAnEmptyReply(t *testing.T) {
+       whatsapp, fake := whatsappStartTestLinked(t)
+       require.NoError(t, whatsapp.device.Contacts.PutContactName(t.Context(), whatsappTestAna, "Ana", "Ana Souza"))
+
+       server := newModelFake(t)
+       server.reply = func(w http.ResponseWriter, call ModelFakeCall) {
+               modelWriteEvents(w, modelCompletedEvent([]any{modelMessageItem("")}, 100, 0, 5))
+       }
+
+       telegram := newTelegramFake(t)
+       bot, _ := telegramStartTestBot(t, telegram)
+       socket, memory := daemonStartTestWithWhatsApp(t, server, bot, whatsapp)
+       client := terminalStartTestClient(t, socket)
+       client.WaitFor(t, "[connected to OneChat]")
+       <-fake.connects
+
+       at := time.Date(2026, 1, 1, 12, 0, 0, 0, time.UTC)
+       require.True(t, fake.Emit(whatsappTestMessage(whatsappTestAna, whatsappTestAna, "m1", "Are you at home?", at)))
+       require.True(t, fake.Emit(whatsappTestMessage(whatsappTestAna, whatsappTestOwn, "m2", "Yes", at)))
+
+       text := "[WhatsApp] Ana Souza, private chat 15550002222@s.whatsapp.net, Thursday 2026-01-01\n12:00 Ana Souza: Are you at home?\n12:00 You: Yes\n" + whatsappBatchEmptyReply
+       client.WaitFor(t, text+"\n[working]\n[done]\n")
+       require.Equal(t, 1, server.Calls())
+       require.Contains(t, string(server.Call(0).raw), "Are you at home?")
+       require.Equal(t, []string{text}, whatsappTestLogTexts(t, memory))
+       require.Empty(t, telegram.Sent())
+       require.Eventually(t, func() bool {
+               return len(whatsapp.batches.Closed()) == 0
+       }, 10*time.Second, time.Millisecond)
+}
+
+func TestWhatsAppGroupTurns(t *testing.T) {
+       testCases := []struct {
+               name    string
+               message func(event *events.Message)
+               line    string
+               turn    bool
+       }{
+               {
+                       name: "plain",
+                       message: func(event *events.Message) {
+                       },
+                       line: "12:00 Bruno Lima: Who brings the cake?",
+               },
+               {
+                       name: "mention",
+                       message: func(event *events.Message) {
+                               event.Message = &waE2E.Message{
+                                       ExtendedTextMessage: &waE2E.ExtendedTextMessage{
+                                               Text: new("@" + whatsappTestLID + " can you bring the cake? Call " + whatsappTestNumber + "."),
+                                               ContextInfo: &waE2E.ContextInfo{
+                                                       MentionedJID: []string{whatsappTestLID + "@lid"},
+                                               },
+                                       },
+                               }
+                       },
+                       line: "12:00 Bruno Lima (mentions you): @you can you bring the cake? Call OWN.",
+                       turn: true,
+               },
+               {
+                       name: "reply",
+                       message: func(event *events.Message) {
+                               event.Message = &waE2E.Message{
+                                       ExtendedTextMessage: &waE2E.ExtendedTextMessage{
+                                               Text: new("Who brings the cake?"),
+                                               ContextInfo: &waE2E.ContextInfo{
+                                                       Participant: new(whatsappTestOwn.String()),
+                                               },
+                                       },
+                               }
+                       },
+                       line: "12:00 Bruno Lima (replies to you): Who brings the cake?",
+                       turn: true,
+               },
+       }
+
+       for _, tc := range testCases {
+               t.Run(tc.name, func(t *testing.T) {
+                       whatsapp, fake := whatsappStartTestLinked(t)
+                       fake.groups = []*types.GroupInfo{
+                               {
+                                       JID: whatsappTestFamily,
+                                       GroupName: types.GroupName{
+                                               Name: "Family",
+                                       },
+                               },
+                       }
+
+                       server := newModelFake(t)
+                       socket, memory := daemonStartTestWithWhatsApp(t, server, nil, whatsapp)
+                       client := terminalStartTestClient(t, socket)
+                       client.WaitFor(t, "[connected to OneChat]")
+                       <-fake.connects
+
+                       event := whatsappTestMessage(whatsappTestFamily, whatsappTestBruno, "m1", "Who brings the cake?", time.Date(2026, 1, 1, 12, 0, 0, 0, time.UTC))
+                       event.Info.PushName = "Bruno Lima"
+                       tc.message(event)
+                       require.True(t, fake.Emit(event))
+
+                       text := "[WhatsApp] Family, group 120363000000000001@g.us, Thursday 2026-01-01\n" + tc.line
+                       if tc.turn {
+                               text += "\n" + whatsappBatchEmptyReply
+                               client.WaitFor(t, "[done]")
+                               require.Equal(t, 1, server.Calls())
+                       } else {
+                               client.WaitFor(t, text)
+                               time.Sleep(100 * time.Millisecond)
+                               require.Zero(t, server.Calls())
+                       }
+
+                       require.Equal(t, text, whatsappTestLogTexts(t, memory)[0])
+               })
+       }
+}
+
+func TestWhatsAppTakesOnlyText(t *testing.T) {
+       at := time.Date(2026, 1, 1, 12, 0, 0, 0, time.UTC)
+       testCases := []struct {
+               name   string
+               change func(event *events.Message)
+       }{
+               {
+                       name: "an edit",
+                       change: func(event *events.Message) {
+                               event.IsEdit = true
+                       },
+               },
+               {
+                       name: "old history",
+                       change: func(event *events.Message) {
+                               event.SourceWebMsg = &waWeb.WebMessageInfo{}
+                       },
+               },
+               {
+                       name: "a view-once message",
+                       change: func(event *events.Message) {
+                               event.IsViewOnce = true
+                       },
+               },
+               {
+                       name: "a disappearing message",
+                       change: func(event *events.Message) {
+                               event.IsEphemeral = true
+                       },
+               },
+               {
+                       name: "the chat of the user with itself",
+                       change: func(event *events.Message) {
+                               event.Info.Chat = whatsappTestOwn
+                       },
+               },
+               {
+                       name: "a status broadcast",
+                       change: func(event *events.Message) {
+                               event.Info.Chat = types.StatusBroadcastJID
+                       },
+               },
+               {
+                       name: "a photo with a caption",
+                       change: func(event *events.Message) {
+                               event.Message = &waE2E.Message{
+                                       ImageMessage: &waE2E.ImageMessage{
+                                               Caption: new("look"),
+                                       },
+                               }
+                       },
+               },
+               {
+                       name: "a text of spaces",
+                       change: func(event *events.Message) {
+                               event.Message.Conversation = new("  ")
+                       },
+               },
+       }
+
+       for _, tc := range testCases {
+               t.Run(tc.name, func(t *testing.T) {
+                       whatsapp, _ := whatsappStartTestLinked(t)
+                       event := whatsappTestMessage(whatsappTestAna, whatsappTestAna, "m1", "hi", at)
+                       tc.change(event)
+                       require.True(t, whatsapp.handle(event))
+                       require.NoError(t, whatsapp.batches.CloseAll())
+                       require.Empty(t, whatsapp.batches.Closed())
+               })
+       }
+}
+
+// whatsappStartTestLinked opens a WhatsApp with a linked device in a temporary
+// directory, with a quiet time of 50 ms for its batches.
+func whatsappStartTestLinked(t *testing.T) (*WhatsApp, *WhatsAppFake) {
+       t.Helper()
+
+       dir := t.TempDir()
+       whatsappTestSession(t, dir, true)
+       whatsapp, fake, _ := whatsappStartTest(t, dir, newTestClock())
+       whatsapp.batches.quiet = 50 * time.Millisecond
+
+       return whatsapp, fake
+}