]> git.giacomolli.uk - onechat/blob - whatsapp_test.go
Show the WhatsApp link with /whatsapp status
[onechat] / whatsapp_test.go
1 package main
2
3 import (
4 "context"
5 "io"
6 "log"
7 "os"
8 "path/filepath"
9 "testing"
10 "time"
11
12 "github.com/stretchr/testify/require"
13 "go.mau.fi/whatsmeow/types/events"
14 )
15
16 func TestWhatsAppStatusFollowsTheConnection(t *testing.T) {
17 dir := t.TempDir()
18 whatsappTestSession(t, dir, true)
19 clock := newTestClock()
20 fake := &WhatsAppFake{
21 connected: make(chan struct{}),
22 }
23
24 whatsapp, err := openWhatsApp(t.Context(), dir, clock.Now, log.New(io.Discard, "", 0), fake.newClient)
25 require.NoError(t, err)
26
27 t.Cleanup(func() {
28 require.NoError(t, whatsapp.Close())
29 })
30
31 ctx, cancel := context.WithCancel(t.Context())
32 done := make(chan struct{})
33 go func() {
34 defer close(done)
35
36 whatsapp.Run(ctx)
37 }()
38
39 t.Cleanup(func() {
40 cancel()
41 <-done
42 })
43
44 <-fake.connected
45 require.Equal(t, "WhatsApp is linked and not connected yet.", whatsapp.Status())
46
47 require.True(t, fake.Emit(&events.Connected{}))
48 require.Equal(t, "WhatsApp is linked and connected since 2026-01-01 12:00.", whatsapp.Status())
49
50 clock.now = clock.now.Add(20 * time.Minute)
51 require.True(t, fake.Emit(&events.Disconnected{}))
52 clock.now = clock.now.Add(time.Minute)
53 require.True(t, fake.Emit(&events.Disconnected{}))
54 require.Equal(t, "WhatsApp is linked and disconnected since 2026-01-01 12:20. The last connection started at 2026-01-01 12:00.", whatsapp.Status())
55 }
56
57 func TestWhatsAppStatusOfAFirstConnectionThatFailed(t *testing.T) {
58 dir := t.TempDir()
59 whatsappTestSession(t, dir, true)
60 whatsapp, fake := whatsappStartTest(t, dir)
61
62 ctx, cancel := context.WithCancel(t.Context())
63 done := make(chan struct{})
64 go func() {
65 defer close(done)
66
67 whatsapp.Run(ctx)
68 }()
69
70 t.Cleanup(func() {
71 cancel()
72 <-done
73 })
74
75 <-fake.connected
76 require.True(t, fake.Emit(&events.Disconnected{}))
77 require.Equal(t, "WhatsApp is linked and disconnected since 2026-01-01 12:00.", whatsapp.Status())
78 }
79
80 func TestWhatsAppIsNotLinkedWithoutALinkedDevice(t *testing.T) {
81 testCases := []struct {
82 name string
83 session func(t *testing.T, dir string)
84 }{
85 {
86 name: "no session file",
87 session: func(t *testing.T, dir string) {
88 },
89 },
90 {
91 name: "a session of a pairing that did not end",
92 session: func(t *testing.T, dir string) {
93 whatsappTestSession(t, dir, false)
94 },
95 },
96 }
97
98 for _, tc := range testCases {
99 t.Run(tc.name, func(t *testing.T) {
100 dir := t.TempDir()
101 tc.session(t, dir)
102 whatsapp, _ := whatsappStartTest(t, dir)
103 require.Equal(t, "WhatsApp is not linked.", whatsapp.Status())
104 })
105 }
106 }
107
108 func TestWhatsAppRefusesASessionThatOthersCanRead(t *testing.T) {
109 dir := t.TempDir()
110 whatsappTestSession(t, dir, true)
111 require.NoError(t, os.Chmod(filepath.Join(dir, whatsappDirName, whatsappSessionFileName), 0o644))
112
113 _, err := openWhatsApp(t.Context(), dir, time.Now, log.New(io.Discard, "", 0), whatsappNewClient)
114 require.EqualError(t, err, "whatsapp/session.db holds the WhatsApp session, so its mode must be 0600")
115 }
116
117 func TestWhatsAppCommandsAnswerOnlyTheClientThatAsked(t *testing.T) {
118 server := newModelFake(t)
119 telegram := newTelegramFake(t)
120 bot, _ := telegramStartTestBot(t, telegram)
121 socket := daemonStartTestWithBot(t, server, bot)
122 asking := terminalStartTestClient(t, socket)
123 other := terminalStartTestClient(t, socket)
124 asking.WaitFor(t, "[connected to OneChat]")
125 other.WaitFor(t, "[connected to OneChat]")
126
127 asking.Type("/whatsapp status")
128 asking.WaitFor(t, "WhatsApp is not linked.")
129 asking.Type(" /whatsapp unknown ")
130 asking.WaitFor(t, whatsappUsage)
131
132 telegram.Add(TelegramUpdate{
133 UpdateID: 1,
134 Message: telegramOwnerMessage("/whatsapp status"),
135 })
136
137 telegramWaitForSent(t, telegram, "WhatsApp is not linked.")
138 require.Equal(t, []string{"WhatsApp is not linked."}, telegram.Sent())
139 require.Equal(t, "[connected to OneChat]\n", other.Output())
140 require.Zero(t, server.Calls())
141 }
142
143 func TestWhatsAppCommandArgs(t *testing.T) {
144 testCases := []struct {
145 name string
146 line string
147 args string
148 found bool
149 }{
150 {
151 name: "a command with its arguments",
152 line: " /whatsapp pair +1 555 ",
153 args: "pair +1 555",
154 found: true,
155 },
156 {
157 name: "the command alone",
158 line: "/whatsapp",
159 args: "",
160 found: true,
161 },
162 {
163 name: "a word that starts with the command",
164 line: "/whatsappstatus",
165 args: "",
166 found: false,
167 },
168 {
169 name: "a message that names the command",
170 line: "what does /whatsapp status do?",
171 args: "",
172 found: false,
173 },
174 }
175
176 for _, tc := range testCases {
177 t.Run(tc.name, func(t *testing.T) {
178 args, found := whatsappCommandArgs(tc.line)
179 require.Equal(t, tc.args, args)
180 require.Equal(t, tc.found, found)
181 })
182 }
183 }