Merge pull request 'asks: a replayed tap is said as the answer already recorded (issue 393)' (#78) from fix/393-asks-replayed-tap into main
This commit was merged in pull request #78.
This commit is contained in:
@@ -27,6 +27,11 @@ type fakeTelegram struct {
|
||||
msgID int64
|
||||
taps int // answerCallbackQuery calls
|
||||
deleted int
|
||||
// toasts are the words a tap's acknowledgement showed over the chat (answerCallbackQuery), by the chat the
|
||||
// tap came from: what the phone shows the tapper and never puts in the chat. Kept apart from sent, so a
|
||||
// chat's messages stay what the chat holds.
|
||||
toasts []tgMessage
|
||||
tappedIn map[string]int64 // a tap's callback id to the chat it came from
|
||||
}
|
||||
|
||||
// tgMessage is one message the bot sent or edited: its chat, its id, its words and its buttons (label →
|
||||
@@ -108,9 +113,18 @@ func (f *fakeTelegram) serve(w http.ResponseWriter, r *http.Request) {
|
||||
f.t.Logf("phone: %s to %d (#%d): %q %v", method, chat, m.ID, firstLine(text), m.Buttons)
|
||||
ok(map[string]any{"message_id": m.ID, "chat": map[string]any{"id": chat, "type": "private"}, "text": text})
|
||||
case "answerCallbackQuery":
|
||||
id, _ := body["callback_query_id"].(string)
|
||||
text, _ := body["text"].(string)
|
||||
f.mu.Lock()
|
||||
f.taps++
|
||||
chat, known := f.tappedIn[id]
|
||||
if known && text != "" {
|
||||
f.toasts = append(f.toasts, tgMessage{Chat: chat, Text: text, At: time.Now()})
|
||||
}
|
||||
f.mu.Unlock()
|
||||
if text != "" {
|
||||
f.t.Logf("phone: answerCallbackQuery %s in %d: %q", id, chat, firstLine(text))
|
||||
}
|
||||
ok(true)
|
||||
case "deleteMessage":
|
||||
f.mu.Lock()
|
||||
@@ -152,7 +166,14 @@ func (f *fakeTelegram) tapped(from int64, chat int64, chatType string, onMessage
|
||||
// tappedOn is a tap on a message showing the words given: what a message changed under the operator's thumb,
|
||||
// or forwarded and edited elsewhere, carries.
|
||||
func (f *fakeTelegram) tappedOn(from int64, chat int64, chatType string, onMessage int64, data, text string) {
|
||||
f.push(map[string]any{"callback_query": map[string]any{"id": fmt.Sprintf("cb-%d", f.nextID()), "data": data,
|
||||
id := fmt.Sprintf("cb-%d", f.nextID())
|
||||
f.mu.Lock()
|
||||
if f.tappedIn == nil {
|
||||
f.tappedIn = map[string]int64{}
|
||||
}
|
||||
f.tappedIn[id] = chat
|
||||
f.mu.Unlock()
|
||||
f.push(map[string]any{"callback_query": map[string]any{"id": id, "data": data,
|
||||
"from": map[string]any{"id": from, "is_bot": false, "first_name": fmt.Sprintf("Account %d", from)},
|
||||
"message": map[string]any{"message_id": onMessage, "text": text,
|
||||
"chat": map[string]any{"id": chat, "type": chatType}}}})
|
||||
@@ -197,6 +218,26 @@ func (f *fakeTelegram) waitFor(what string, chat int64, since time.Time, within
|
||||
return tgMessage{}
|
||||
}
|
||||
|
||||
// toldTapper waits for words the phone showed in a chat at or after a time, as a message in it or as a tap's
|
||||
// acknowledgement over it: where the channel says the router's word on a tap (issue 372).
|
||||
func (f *fakeTelegram) toldTapper(what string, chat int64, since time.Time, within time.Duration, match func(string) bool) string {
|
||||
f.t.Helper()
|
||||
deadline := time.Now().Add(within)
|
||||
for time.Now().Before(deadline) {
|
||||
f.mu.Lock()
|
||||
for _, m := range append(append([]tgMessage{}, f.sent...), f.toasts...) {
|
||||
if m.Chat == chat && !m.At.Before(since) && match(m.Text) {
|
||||
f.mu.Unlock()
|
||||
return m.Text
|
||||
}
|
||||
}
|
||||
f.mu.Unlock()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
f.t.Fatalf("the phone never showed %s (chat %d) within %s; it showed:\n%s", what, chat, within, f.transcript())
|
||||
return ""
|
||||
}
|
||||
|
||||
// since is every message to a chat sent at or after a time.
|
||||
func (f *fakeTelegram) since(chat int64, at time.Time) []tgMessage {
|
||||
f.mu.Lock()
|
||||
@@ -218,6 +259,9 @@ func (f *fakeTelegram) transcript() string {
|
||||
fmt.Fprintf(&b, " %s to %d #%d edited=%v %q %v\n", m.At.Format("15:04:05.000"), m.Chat, m.ID, m.Edited,
|
||||
firstLine(m.Text), m.Buttons)
|
||||
}
|
||||
for _, m := range f.toasts {
|
||||
fmt.Fprintf(&b, " %s to %d tap acknowledged %q\n", m.At.Format("15:04:05.000"), m.Chat, firstLine(m.Text))
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
|
||||
+6
-2
@@ -178,11 +178,15 @@ func TestTheOperatorsAnswerEndToEnd(t *testing.T) {
|
||||
})
|
||||
|
||||
// --- 4. A replayed tap, and a redelivered warrant, do nothing more.
|
||||
// The replay is the operator's own answer again: the router says it is the one already recorded (on the tap's
|
||||
// acknowledgement, issue 372), not refused as if the approval failed, and it is no second warrant or act.
|
||||
t.Run("a replayed tap and a redelivered warrant do nothing more", func(t *testing.T) {
|
||||
tapped := time.Now()
|
||||
l.tg.tapped(operatorAccount, operatorAccount, "private", firstMessage.ID, button(firstMessage, "Approve"))
|
||||
l.tg.waitFor("the refusal of a replayed tap", operatorAccount, tapped, 90*time.Second,
|
||||
func(m tgMessage) bool { return strings.Contains(m.Text, "That answer was not taken") })
|
||||
l.tg.toldTapper("that a replayed tap is the answer already recorded", operatorAccount, tapped, 90*time.Second,
|
||||
func(text string) bool {
|
||||
return strings.Contains(text, "You already chose Approve") && strings.Contains(text, "recorded")
|
||||
})
|
||||
time.Sleep(2 * time.Second)
|
||||
if n := a.wordsOn("a1"); n != 1 {
|
||||
t.Errorf("the router said %d words on one ask", n)
|
||||
|
||||
Reference in New Issue
Block a user