X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/2e2524881dfe8f6c5cabfd9d342d5d3492953bd4..7088b82414bdf947a6f88918c0a7b2c7fb0c53ef:/whatsapp_test.go diff --git a/whatsapp_test.go b/whatsapp_test.go index 2bdb4cc..7001ea1 100644 --- a/whatsapp_test.go +++ b/whatsapp_test.go @@ -1,10 +1,7 @@ package main import ( - "crypto/sha256" - "encoding/hex" "errors" - "net/http" "os" "path/filepath" "strings" @@ -40,12 +37,38 @@ func TestWhatsAppStatusFollowsTheConnection(t *testing.T) { func TestWhatsAppStatusOfAFirstConnectionThatFailed(t *testing.T) { dir := t.TempDir() whatsappTestSession(t, dir, true) - whatsapp, fake, _ := whatsappStartTest(t, dir, newTestClock()) + whatsapp, fake, logs := whatsappStartTest(t, dir, newTestClock()) daemonStartTestWithWhatsApp(t, newModelFake(t), nil, whatsapp) <-fake.connects require.True(t, fake.Emit(&events.Disconnected{})) require.Equal(t, "WhatsApp is linked and disconnected since 2026-01-01 12:00.", whatsapp.Status()) + require.Equal(t, "first connect failed, retrying\n", logs.String()) +} + +func TestWhatsAppLogsEachChangeOfTheConnectionOnce(t *testing.T) { + dir := t.TempDir() + whatsappTestSession(t, dir, true) + clock := newTestClock() + whatsapp, fake, logs := whatsappStartTest(t, dir, clock) + daemonStartTestWithWhatsApp(t, newModelFake(t), nil, whatsapp) + + <-fake.connects + require.True(t, fake.Emit(&events.Connected{})) + clock.now = clock.now.Add(time.Minute) + require.True(t, fake.Emit(&events.Disconnected{})) + clock.now = clock.now.Add(time.Minute) + require.True(t, fake.Emit(&events.Disconnected{})) + clock.now = clock.now.Add(25 * time.Second) + require.True(t, fake.Emit(&events.Connected{})) + + require.Equal(t, []string{ + "connected", + "disconnected, retrying", + "connected again after 1m25s", + }, strings.Split(strings.TrimSuffix(logs.String(), "\n"), "\n")) + require.NotContains(t, logs.String(), whatsappTestNumber) + require.NotContains(t, logs.String(), whatsappTestLID) } func TestWhatsAppIsNotLinkedWithoutALinkedDevice(t *testing.T) { @@ -373,7 +396,7 @@ func TestWhatsAppLogsNoOwnNumber(t *testing.T) { require.Eventually(t, func() bool { return logs.String() != "" }, 10*time.Second, time.Millisecond) - require.Equal(t, "connect: no route for OWN@s.whatsapp.net and OWN@lid\n", logs.String()) + require.Equal(t, "connect failed, restart to retry: no route for OWN@s.whatsapp.net and OWN@lid\n", logs.String()) } func TestWhatsAppPhone(t *testing.T) { @@ -464,194 +487,3 @@ func TestSubagentHasNoWhatsAppTools(t *testing.T) { require.Equal(t, `error: unknown tool "whatsapp_find"`, box.run(t.Context(), "whatsapp_find", `{"name":"ana"}`)) require.Equal(t, `error: unknown tool "whatsapp_send"`, box.run(t.Context(), "whatsapp_send", `{"id":"a","chat":"15550002222@s.whatsapp.net","text":"hi"}`)) } - -func TestWhatsAppSendSendsOnceForEachID(t *testing.T) { - whatsapp, fake := whatsappStartTestLinked(t) - whatsappTestContacts(t, whatsapp) - daemonStartTestWithWhatsApp(t, newModelFake(t), nil, whatsapp) - whatsappTestConnect(t, fake) - - answer, err := whatsapp.Send(t.Context(), "keys", whatsappTestAna.String(), "The keys are under the mat.") - require.NoError(t, err) - require.Equal(t, "Sent to Ana Souza at 12:05.", answer) - - answer, err = whatsapp.Send(t.Context(), "keys", whatsappTestAna.String(), "The keys are under the mat.") - require.NoError(t, err) - require.Equal(t, "Sent to Ana Souza at 12:05. This is the answer of the first call with this id: nothing was sent again.", answer) - - _, err = whatsapp.Send(t.Context(), "keys", whatsappTestAna.String(), "Another text.") - require.EqualError(t, err, "the id keys belongs to another message: give a new id for each message") - - require.Equal(t, []WhatsAppFakeSend{ - { - to: whatsappTestAna.String(), - text: "The keys are under the mat.", - id: "MSG1", - }, - }, fake.Sent()) - - again, err := openWhatsAppState(filepath.Join(whatsapp.dir, whatsappStateFileName), whatsappBatchQuiet, whatsappBatchWindow) - require.NoError(t, err) - - record, found := again.Send("keys") - require.True(t, found) - require.Equal(t, whatsappSent, record.State) - require.Equal(t, "MSG1", record.MessageID) -} - -func TestWhatsAppSendToAGroup(t *testing.T) { - whatsapp, fake := whatsappStartTestLinked(t) - fake.groups = []*types.GroupInfo{ - { - JID: whatsappTestFamily, - GroupName: types.GroupName{ - Name: "Family", - }, - }, - } - - daemonStartTestWithWhatsApp(t, newModelFake(t), nil, whatsapp) - whatsappTestConnect(t, fake) - - answer, err := whatsapp.Send(t.Context(), "cake", whatsappTestFamily.String(), "I bring the cake.") - require.NoError(t, err) - require.Equal(t, "Sent to Family at 12:05.", answer) -} - -func TestWhatsAppSendThatFails(t *testing.T) { - whatsapp, fake := whatsappStartTestLinked(t) - fake.sendErr = errors.New("server error for " + whatsappTestNumber) - daemonStartTestWithWhatsApp(t, newModelFake(t), nil, whatsapp) - whatsappTestConnect(t, fake) - - for range 2 { - answer, err := whatsapp.Send(t.Context(), "keys", whatsappTestAna.String(), "hi") - require.NoError(t, err) - require.True(t, strings.HasPrefix(answer, "The send failed: server error for OWN."), answer) - } - - require.Len(t, fake.Sent(), 1) -} - -func TestWhatsAppSendCutByAStop(t *testing.T) { - whatsapp, fake := whatsappStartTestLinked(t) - daemonStartTestWithWhatsApp(t, newModelFake(t), nil, whatsapp) - whatsappTestConnect(t, fake) - - digest := sha256.Sum256([]byte("hi")) - require.NoError(t, whatsapp.state.PutSend(WhatsAppSend{ - ID: "keys", - Chat: whatsappTestAna.String(), - Digest: hex.EncodeToString(digest[:]), - State: whatsappSending, - })) - - answer, err := whatsapp.Send(t.Context(), "keys", whatsappTestAna.String(), "hi") - require.NoError(t, err) - require.Contains(t, answer, "its result is unknown") - require.Empty(t, fake.Sent()) -} - -func TestWhatsAppSendRefuses(t *testing.T) { - testCases := []struct { - name string - id string - chat string - text string - err string - }{ - { - name: "no id", - id: " ", - chat: whatsappTestAna.String(), - text: "hi", - err: "the id must have 1 to 100 bytes", - }, - { - name: "no text", - id: "a", - chat: whatsappTestAna.String(), - text: "", - err: "the text must have 1 to 65536 bytes", - }, - { - name: "a name for a chat", - id: "a", - chat: "Ana Souza", - text: "hi", - err: `"Ana Souza" is not the ID of a WhatsApp chat: find the ID with whatsapp_find`, - }, - { - name: "a status broadcast", - id: "a", - chat: types.StatusBroadcastJID.String(), - text: "hi", - err: `"status@broadcast" is not a private chat or a group`, - }, - { - name: "the chat of the user", - id: "a", - chat: whatsappTestOwn.String(), - text: "hi", - err: "this is the chat of the user with itself: send to another chat", - }, - } - - whatsapp, fake := whatsappStartTestLinked(t) - daemonStartTestWithWhatsApp(t, newModelFake(t), nil, whatsapp) - whatsappTestConnect(t, fake) - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - _, err := whatsapp.Send(t.Context(), tc.id, tc.chat, tc.text) - require.EqualError(t, err, tc.err) - }) - } - - require.Empty(t, fake.Sent()) -} - -func TestWhatsAppSendWhileDisconnected(t *testing.T) { - whatsapp, fake := whatsappStartTestLinked(t) - daemonStartTestWithWhatsApp(t, newModelFake(t), nil, whatsapp) - whatsappTestConnect(t, fake) - require.True(t, fake.Emit(&events.Disconnected{})) - - _, err := whatsapp.Send(t.Context(), "keys", whatsappTestAna.String(), "hi") - require.EqualError(t, err, "WhatsApp is disconnected, so nothing was sent: try again later") - - require.True(t, fake.Emit(&events.Connected{})) - answer, err := whatsapp.Send(t.Context(), "keys", whatsappTestAna.String(), "hi") - require.NoError(t, err) - require.Equal(t, "Sent to +15550002222 at 12:05.", answer) -} - -func TestWhatsAppSendWithoutALink(t *testing.T) { - whatsapp, _, _ := whatsappStartTest(t, t.TempDir(), newTestClock()) - - answer, err := whatsapp.Send(t.Context(), "keys", whatsappTestAna.String(), "hi") - require.NoError(t, err) - require.Equal(t, whatsappNotLinked, answer) -} - -func TestAgentSendsAWhatsAppMessage(t *testing.T) { - whatsapp, fake := whatsappStartTestLinked(t) - whatsappTestContacts(t, whatsapp) - server := newModelFake(t) - server.reply = func(w http.ResponseWriter, call ModelFakeCall) { - if call.number == 0 { - modelWriteEvents(w, modelCompletedEvent([]any{modelFunctionCallItem("fc_1", "call_1", "whatsapp_send", `{"id":"keys","chat":"15550002222@s.whatsapp.net","text":"The keys are under the mat."}`)}, 100, 0, 5)) - return - } - - modelWriteEvents(w, modelCompletedEvent([]any{modelMessageItem("Sent.")}, 100, 0, 5)) - } - - socket, _ := daemonStartTestWithWhatsApp(t, server, nil, whatsapp) - client := terminalStartTestClient(t, socket) - whatsappTestConnect(t, fake) - - client.Type("Tell Ana that the keys are under the mat.") - client.WaitFor(t, "[result] Sent to Ana Souza at 12:05.\nSent.\n[done]") - require.Len(t, fake.Sent(), 1) -}