Merge main into replay/368: the asks check fixed for issue 393 (#78)
This commit is contained in:
@@ -27,6 +27,11 @@ type fakeTelegram struct {
|
|||||||
msgID int64
|
msgID int64
|
||||||
taps int // answerCallbackQuery calls
|
taps int // answerCallbackQuery calls
|
||||||
deleted int
|
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 →
|
// 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)
|
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})
|
ok(map[string]any{"message_id": m.ID, "chat": map[string]any{"id": chat, "type": "private"}, "text": text})
|
||||||
case "answerCallbackQuery":
|
case "answerCallbackQuery":
|
||||||
|
id, _ := body["callback_query_id"].(string)
|
||||||
|
text, _ := body["text"].(string)
|
||||||
f.mu.Lock()
|
f.mu.Lock()
|
||||||
f.taps++
|
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()
|
f.mu.Unlock()
|
||||||
|
if text != "" {
|
||||||
|
f.t.Logf("phone: answerCallbackQuery %s in %d: %q", id, chat, firstLine(text))
|
||||||
|
}
|
||||||
ok(true)
|
ok(true)
|
||||||
case "deleteMessage":
|
case "deleteMessage":
|
||||||
f.mu.Lock()
|
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,
|
// 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.
|
// or forwarded and edited elsewhere, carries.
|
||||||
func (f *fakeTelegram) tappedOn(from int64, chat int64, chatType string, onMessage int64, data, text string) {
|
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)},
|
"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,
|
"message": map[string]any{"message_id": onMessage, "text": text,
|
||||||
"chat": map[string]any{"id": chat, "type": chatType}}}})
|
"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{}
|
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.
|
// since is every message to a chat sent at or after a time.
|
||||||
func (f *fakeTelegram) since(chat int64, at time.Time) []tgMessage {
|
func (f *fakeTelegram) since(chat int64, at time.Time) []tgMessage {
|
||||||
f.mu.Lock()
|
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,
|
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)
|
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()
|
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.
|
// --- 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) {
|
t.Run("a replayed tap and a redelivered warrant do nothing more", func(t *testing.T) {
|
||||||
tapped := time.Now()
|
tapped := time.Now()
|
||||||
l.tg.tapped(operatorAccount, operatorAccount, "private", firstMessage.ID, button(firstMessage, "Approve"))
|
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,
|
l.tg.toldTapper("that a replayed tap is the answer already recorded", operatorAccount, tapped, 90*time.Second,
|
||||||
func(m tgMessage) bool { return strings.Contains(m.Text, "That answer was not taken") })
|
func(text string) bool {
|
||||||
|
return strings.Contains(text, "You already chose Approve") && strings.Contains(text, "recorded")
|
||||||
|
})
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
if n := a.wordsOn("a1"); n != 1 {
|
if n := a.wordsOn("a1"); n != 1 {
|
||||||
t.Errorf("the router said %d words on one ask", n)
|
t.Errorf("the router said %d words on one ask", n)
|
||||||
|
|||||||
Reference in New Issue
Block a user