|
|
|
@@ -15,7 +15,8 @@ import (
|
|
|
|
|
"time"
|
|
|
|
|
"unicode/utf8"
|
|
|
|
|
|
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/channel"
|
|
|
|
|
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
|
|
|
|
|
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const goodToken = "123456789:AAEhBP0av28P4XFQnIuR-o-7Xnz1kkUzW3g"
|
|
|
|
@@ -184,15 +185,15 @@ func (s *said) waited() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func work(verb string, m channel.Message) (string, json.RawMessage) {
|
|
|
|
|
func work(verb string, m oc.Message) (string, json.RawMessage) {
|
|
|
|
|
raw, _ := json.Marshal(m)
|
|
|
|
|
return channel.ChannelSubject(verb, Kind), raw
|
|
|
|
|
return occ.ChannelSubject(verb, Kind), raw
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestAQuestionIsShownWithItsTicketsAndRingsAndAWarningIsSilent(t *testing.T) {
|
|
|
|
|
c, f, _, st := newChannel(t, goodToken)
|
|
|
|
|
subject, body := work(channel.Show, channel.Message{Handle: "m1", Title: "Delivery of hq held", Body: "Needs you: release it.",
|
|
|
|
|
To: "42", Buttons: []channel.Button{{Label: "Release", Ticket: "0123456789abcdef0123456789abcdef"}}})
|
|
|
|
|
subject, body := work(occ.Show, oc.Message{Handle: "m1", Title: "Delivery of hq held", Body: "Needs you: release it.",
|
|
|
|
|
To: "42", Buttons: []oc.Button{{Label: "Release", Ticket: "0123456789abcdef0123456789abcdef"}}})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
@@ -212,12 +213,12 @@ func TestAQuestionIsShownWithItsTicketsAndRingsAndAWarningIsSilent(t *testing.T)
|
|
|
|
|
if st.placed["m1"].ID == 0 {
|
|
|
|
|
t.Error("where it is was not kept")
|
|
|
|
|
}
|
|
|
|
|
subject, body = work(channel.Send, channel.Message{Handle: "m2", Title: "Resolved: hq works again", To: "42"})
|
|
|
|
|
subject, body = work(occ.Send, oc.Message{Handle: "m2", Title: "Resolved: hq works again", To: "42"})
|
|
|
|
|
_ = c.Take(subject, body)
|
|
|
|
|
if f.of("sendMessage")[1].Body["disable_notification"] != true {
|
|
|
|
|
t.Error("a clearing rang (D4)")
|
|
|
|
|
}
|
|
|
|
|
subject, body = work(channel.Send, channel.Message{Handle: "m3", Title: "Urgent: ace silent", Urgent: true, To: "42"})
|
|
|
|
|
subject, body = work(occ.Send, oc.Message{Handle: "m3", Title: "Urgent: ace silent", Urgent: true, To: "42"})
|
|
|
|
|
_ = c.Take(subject, body)
|
|
|
|
|
if f.of("sendMessage")[2].Body["disable_notification"] != false {
|
|
|
|
|
t.Error("an urgent message was silent (D4)")
|
|
|
|
@@ -226,7 +227,7 @@ func TestAQuestionIsShownWithItsTicketsAndRingsAndAWarningIsSilent(t *testing.T)
|
|
|
|
|
|
|
|
|
|
func TestALongMessageIsCutAndTheCutSaid(t *testing.T) {
|
|
|
|
|
c, f, _, _ := newChannel(t, goodToken)
|
|
|
|
|
subject, body := work(channel.Send, channel.Message{Handle: "m1", Title: "t", Body: strings.Repeat("x", 5000), To: "42"})
|
|
|
|
|
subject, body := work(occ.Send, oc.Message{Handle: "m1", Title: "t", Body: strings.Repeat("x", 5000), To: "42"})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
@@ -243,10 +244,10 @@ func TestALongMessageIsCutAndTheCutSaid(t *testing.T) {
|
|
|
|
|
// nor injects. The tap on it is still compared by the plain words, which is what Telegram gives back.
|
|
|
|
|
func TestAMessageIsRenderedInHTMLWithItsMarkupEscaped(t *testing.T) {
|
|
|
|
|
c, f, s, _ := newChannel(t, goodToken)
|
|
|
|
|
subject, body := work(channel.Show, channel.Message{Handle: "q1", Title: "Set mounts on <shanks> & co?",
|
|
|
|
|
subject, body := work(occ.Show, oc.Message{Handle: "q1", Title: "Set mounts on <shanks> & co?",
|
|
|
|
|
Body: "Changes two settings.\n+ shares: media=/storage/media\n~ sources: a=b (was: c)",
|
|
|
|
|
Note: "Asked by mesh-controller at 15:11.\nFingerprint 1234 5678 9abc.",
|
|
|
|
|
To: "42", Buttons: []channel.Button{{Label: "Approve", Ticket: "tkt"}}})
|
|
|
|
|
To: "42", Buttons: []oc.Button{{Label: "Approve", Ticket: "tkt"}}})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
@@ -264,7 +265,7 @@ func TestAMessageIsRenderedInHTMLWithItsMarkupEscaped(t *testing.T) {
|
|
|
|
|
Message: &Msg{MessageID: shown, Chat: Chat{ID: 42, Type: "private"},
|
|
|
|
|
Text: "Set mounts on <shanks> & co?\nChanges two settings.\n+ shares: media=/storage/media\n~ sources: a=b (was: c)\n" +
|
|
|
|
|
"Asked by mesh-controller at 15:11.\nFingerprint 1234 5678 9abc."}}})
|
|
|
|
|
if got := s.of(channel.IntakeSubject(channel.Chosen, Kind)); len(got) != 1 {
|
|
|
|
|
if got := s.of(occ.IntakeSubject(occ.Chosen, Kind)); len(got) != 1 {
|
|
|
|
|
t.Fatalf("the tap on the rendered message was not taken: %s", got)
|
|
|
|
|
}
|
|
|
|
|
// Words changed by another holder of the token are still told apart.
|
|
|
|
@@ -272,11 +273,11 @@ func TestAMessageIsRenderedInHTMLWithItsMarkupEscaped(t *testing.T) {
|
|
|
|
|
Message: &Msg{MessageID: shown, Chat: Chat{ID: 42, Type: "private"},
|
|
|
|
|
Text: "Set mounts on <shanks> & co?\nChanges three settings.\n+ shares: media=/storage/media\n~ sources: a=b (was: c)\n" +
|
|
|
|
|
"Asked by mesh-controller at 15:11.\nFingerprint 1234 5678 9abc."}}})
|
|
|
|
|
if got := s.of(channel.IntakeSubject(channel.Chosen, Kind)); len(got) != 1 {
|
|
|
|
|
if got := s.of(occ.IntakeSubject(occ.Chosen, Kind)); len(got) != 1 {
|
|
|
|
|
t.Fatalf("a tap on changed words was taken: %s", got)
|
|
|
|
|
}
|
|
|
|
|
// The edit says what was chosen, one line with the headline, and is in the same mode.
|
|
|
|
|
subject, body = work(channel.Edit, channel.Message{Handle: "q1", Title: "You chose Approve at 15:06 on Telegram · Set mounts on <shanks> & co?",
|
|
|
|
|
subject, body = work(occ.Edit, oc.Message{Handle: "q1", Title: "You chose Approve at 15:06 on Telegram · Set mounts on <shanks> & co?",
|
|
|
|
|
Note: "Told to mesh-controller, which acts on it itself.", To: "42"})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
@@ -302,7 +303,7 @@ func TestATapOnAMessageShownBeforeIsStillTaken(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
c.Handle(Update{UpdateID: 1, Callback: &Callback{ID: "cb1", Data: "tkt", From: User{ID: 42, FirstName: "Jo"},
|
|
|
|
|
Message: &Msg{MessageID: 9, Chat: Chat{ID: 42, Type: "private"}, Text: words}}})
|
|
|
|
|
if got := s.of(channel.IntakeSubject(channel.Chosen, Kind)); len(got) != 1 {
|
|
|
|
|
if got := s.of(occ.IntakeSubject(occ.Chosen, Kind)); len(got) != 1 {
|
|
|
|
|
t.Fatalf("the tap on a message shown before was not taken: %s", got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -313,8 +314,8 @@ func TestAnEditToTheSameTextIsASuccessAndAGoneMessageIsSentAgain(t *testing.T) {
|
|
|
|
|
f.answer["editMessageText"] = func(map[string]any) (int, string) {
|
|
|
|
|
return 400, `{"ok":false,"error_code":400,"description":"Bad Request: message is not modified"}`
|
|
|
|
|
}
|
|
|
|
|
subject, body := work(channel.Edit, channel.Message{Handle: "m1", Title: "same", To: "42"})
|
|
|
|
|
if err := c.Take(subject, body); err != nil || len(f.of("sendMessage")) != 0 || len(s.of(channel.IntakeSubject(channel.FailedWhat, Kind))) != 0 {
|
|
|
|
|
subject, body := work(occ.Edit, oc.Message{Handle: "m1", Title: "same", To: "42"})
|
|
|
|
|
if err := c.Take(subject, body); err != nil || len(f.of("sendMessage")) != 0 || len(s.of(occ.IntakeSubject(occ.FailedWhat, Kind))) != 0 {
|
|
|
|
|
t.Fatalf("an identical edit was not a success (D6): %v", err)
|
|
|
|
|
}
|
|
|
|
|
f.answer["editMessageText"] = func(map[string]any) (int, string) {
|
|
|
|
@@ -341,21 +342,21 @@ func TestARefusalIsPermanentARateLimitIsWaitedOutAndNeitherCarriesTheToken(t *te
|
|
|
|
|
}
|
|
|
|
|
return 403, `{"ok":false,"error_code":403,"description":"Forbidden: bot was blocked by the user ` + goodToken + `"}`
|
|
|
|
|
}
|
|
|
|
|
subject, body := work(channel.Send, channel.Message{Handle: "m1", Title: "x", To: "42"})
|
|
|
|
|
subject, body := work(occ.Send, oc.Message{Handle: "m1", Title: "x", To: "42"})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if len(slept) != 1 || slept[0] != 7*time.Second || tries != 2 {
|
|
|
|
|
t.Errorf("the rate limit was not waited out as told (D5): slept %v, tries %d", slept, tries)
|
|
|
|
|
}
|
|
|
|
|
failed := s.of(channel.IntakeSubject(channel.FailedWhat, Kind))
|
|
|
|
|
failed := s.of(occ.IntakeSubject(occ.FailedWhat, Kind))
|
|
|
|
|
if len(failed) != 1 || !strings.Contains(string(failed[0]), `"permanent":true`) || strings.Contains(string(failed[0]), goodToken) {
|
|
|
|
|
t.Fatalf("the refusal: %s (D6)", failed)
|
|
|
|
|
}
|
|
|
|
|
// No linked account and nothing to reply to: said as failed for good, never retried.
|
|
|
|
|
subject, body = work(channel.Send, channel.Message{Handle: "m2", Title: "x"})
|
|
|
|
|
subject, body = work(occ.Send, oc.Message{Handle: "m2", Title: "x"})
|
|
|
|
|
_ = c.Take(subject, body)
|
|
|
|
|
if f := s.of(channel.IntakeSubject(channel.FailedWhat, Kind)); len(f) != 2 || !strings.Contains(string(f[1]), "no account is linked") {
|
|
|
|
|
if f := s.of(occ.IntakeSubject(occ.FailedWhat, Kind)); len(f) != 2 || !strings.Contains(string(f[1]), "no account is linked") {
|
|
|
|
|
t.Errorf("%s", f)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -365,10 +366,10 @@ func TestATapIsAcknowledgedAtOnceAndSaidWithItsAuthenticatedSender(t *testing.T)
|
|
|
|
|
shown := showQuestion(t, c, f)
|
|
|
|
|
c.Handle(Update{UpdateID: 1, Callback: &Callback{ID: "cb1", Data: "tkt", From: User{ID: 42, FirstName: "Jo"},
|
|
|
|
|
Message: &Msg{MessageID: shown, Chat: Chat{ID: 42, Type: "private"}, Text: "Release it?\nThe delivery is held."}}})
|
|
|
|
|
got := s.of(channel.IntakeSubject(channel.Chosen, Kind))
|
|
|
|
|
var ch channel.Choice
|
|
|
|
|
got := s.of(occ.IntakeSubject(occ.Chosen, Kind))
|
|
|
|
|
var ch oc.Choice
|
|
|
|
|
if len(got) != 1 || json.Unmarshal(got[0], &ch) != nil || ch.Ticket != "tkt" ||
|
|
|
|
|
!reflect.DeepEqual(ch.Sender, channel.Sender{Identity: "42", Display: "Jo", Authenticated: true}) {
|
|
|
|
|
!reflect.DeepEqual(ch.Sender, oc.Sender{Identity: "42", Display: "Jo", Authenticated: true}) {
|
|
|
|
|
t.Fatalf("said %s", got)
|
|
|
|
|
}
|
|
|
|
|
// In a group, or from another bot, nothing is said: it is nobody's own chat with the bot.
|
|
|
|
@@ -376,7 +377,7 @@ func TestATapIsAcknowledgedAtOnceAndSaidWithItsAuthenticatedSender(t *testing.T)
|
|
|
|
|
Message: &Msg{Chat: Chat{ID: -100, Type: "group"}}}})
|
|
|
|
|
c.Handle(Update{UpdateID: 3, Callback: &Callback{ID: "cb3", Data: "tkt", From: User{ID: 9, IsBot: true},
|
|
|
|
|
Message: &Msg{Chat: Chat{ID: 9, Type: "private"}}}})
|
|
|
|
|
if len(s.of(channel.IntakeSubject(channel.Chosen, Kind))) != 1 {
|
|
|
|
|
if len(s.of(occ.IntakeSubject(occ.Chosen, Kind))) != 1 {
|
|
|
|
|
t.Error("a tap outside the account's own chat was said")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -385,13 +386,13 @@ func TestStartAsksALinkAndACodeIsAProofDeletedFromTheChat(t *testing.T) {
|
|
|
|
|
c, f, s, _ := newChannel(t, goodToken)
|
|
|
|
|
jo := &User{ID: 42, FirstName: "Jo", Username: "jo"}
|
|
|
|
|
c.Handle(Update{UpdateID: 10, Message: &Msg{MessageID: 5, From: jo, Chat: Chat{ID: 42, Type: "private"}, Text: "/start"}})
|
|
|
|
|
var l channel.LinkAsked
|
|
|
|
|
got := s.of(channel.IntakeSubject(channel.Link, Kind))
|
|
|
|
|
var l oc.LinkAsked
|
|
|
|
|
got := s.of(occ.IntakeSubject(occ.Link, Kind))
|
|
|
|
|
if len(got) != 1 || json.Unmarshal(got[0], &l) != nil || l.Sender.Identity != "42" || l.Sender.Display != "Jo (@jo)" {
|
|
|
|
|
t.Fatalf("link %s", got)
|
|
|
|
|
}
|
|
|
|
|
// The router's answer to the link goes to the chat it came from, though nobody is linked yet.
|
|
|
|
|
subject, body := work(channel.Send, channel.Message{Handle: "r1", Title: "Send the code shown on your desk", Reply: l.ID})
|
|
|
|
|
subject, body := work(occ.Send, oc.Message{Handle: "r1", Title: "Send the code shown on your desk", Reply: l.ID})
|
|
|
|
|
if err := c.Take(subject, body); err != nil || len(f.of("sendMessage")) != 1 || f.of("sendMessage")[0].Body["chat_id"] != float64(42) {
|
|
|
|
|
t.Fatalf("the reply did not reach the chat: %v %v", err, f.of("sendMessage"))
|
|
|
|
|
}
|
|
|
|
@@ -439,7 +440,7 @@ func TestStandingSaysWhatIsMissingAndNeverTheToken(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
c.SayStanding()
|
|
|
|
|
c.SayStanding()
|
|
|
|
|
if n := len(said.of(channel.IntakeSubject(channel.StandingWhat, Kind))); n != 1 {
|
|
|
|
|
if n := len(said.of(occ.IntakeSubject(occ.StandingWhat, Kind))); n != 1 {
|
|
|
|
|
t.Errorf("standing said %d times without a change", n)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -449,7 +450,7 @@ func TestPollTakesTheUpdatesAndKeepsTheOffsetAndSaysAConflict(t *testing.T) {
|
|
|
|
|
f.answer["getUpdates"] = func(map[string]any) (int, string) {
|
|
|
|
|
return 200, `{"ok":true,"result":[{"update_id":41,"message":{"message_id":1,"from":{"id":42},"chat":{"id":42,"type":"private"},"text":"/start"}}]}`
|
|
|
|
|
}
|
|
|
|
|
if err := c.Poll(time.Second); err != nil || st.offset != 42 || len(s.of(channel.IntakeSubject(channel.Link, Kind))) != 1 {
|
|
|
|
|
if err := c.Poll(time.Second); err != nil || st.offset != 42 || len(s.of(occ.IntakeSubject(occ.Link, Kind))) != 1 {
|
|
|
|
|
t.Fatalf("%v offset %d", err, st.offset)
|
|
|
|
|
}
|
|
|
|
|
f.answer["getUpdates"] = func(map[string]any) (int, string) {
|
|
|
|
@@ -466,8 +467,8 @@ func TestPollTakesTheUpdatesAndKeepsTheOffsetAndSaysAConflict(t *testing.T) {
|
|
|
|
|
// showQuestion shows one question with a button to the linked account, and answers its message's id.
|
|
|
|
|
func showQuestion(t *testing.T, c *Channel, f *fakeAPI) int64 {
|
|
|
|
|
t.Helper()
|
|
|
|
|
subject, body := work(channel.Show, channel.Message{Handle: "q1", Title: "Release it?", Body: "The delivery is held.",
|
|
|
|
|
To: "42", Buttons: []channel.Button{{Label: "Release", Ticket: "tkt"}}})
|
|
|
|
|
subject, body := work(occ.Show, oc.Message{Handle: "q1", Title: "Release it?", Body: "The delivery is held.",
|
|
|
|
|
To: "42", Buttons: []oc.Button{{Label: "Release", Ticket: "tkt"}}})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
@@ -493,7 +494,7 @@ func TestATapOnAMessageShowingOtherWordsIsRefused(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
tap("cb-other", shown, "Silence it for a week?\nNothing changes.")
|
|
|
|
|
tap("cb-unknown", shown+100, "Release it?\nThe delivery is held.")
|
|
|
|
|
if got := s.of(channel.IntakeSubject(channel.Chosen, Kind)); len(got) != 0 {
|
|
|
|
|
if got := s.of(occ.IntakeSubject(occ.Chosen, Kind)); len(got) != 0 {
|
|
|
|
|
t.Fatalf("a tap on other words was said: %s", got)
|
|
|
|
|
}
|
|
|
|
|
answers := f.of("answerCallbackQuery")
|
|
|
|
@@ -502,16 +503,16 @@ func TestATapOnAMessageShowingOtherWordsIsRefused(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
// The same words, as Telegram gives them back (its line endings, its outer spaces), are taken.
|
|
|
|
|
tap("cb-same", shown, " Release it?\r\nThe delivery is held. ")
|
|
|
|
|
if got := s.of(channel.IntakeSubject(channel.Chosen, Kind)); len(got) != 1 {
|
|
|
|
|
if got := s.of(occ.IntakeSubject(occ.Chosen, Kind)); len(got) != 1 {
|
|
|
|
|
t.Fatalf("the tap on the words shown was not said: %s", got)
|
|
|
|
|
}
|
|
|
|
|
// An edit moves what was shown: the old words are then refused.
|
|
|
|
|
subject, body := work(channel.Edit, channel.Message{Handle: "q1", Title: "Released", Body: "by you", To: "42"})
|
|
|
|
|
subject, body := work(occ.Edit, oc.Message{Handle: "q1", Title: "Released", Body: "by you", To: "42"})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
tap("cb-old", shown, "Release it?\nThe delivery is held.")
|
|
|
|
|
if got := s.of(channel.IntakeSubject(channel.Chosen, Kind)); len(got) != 1 {
|
|
|
|
|
if got := s.of(occ.IntakeSubject(occ.Chosen, Kind)); len(got) != 1 {
|
|
|
|
|
t.Errorf("a tap on words since replaced was said")
|
|
|
|
|
}
|
|
|
|
|
if d, _ := st.Shown(42, shown); d == "" {
|
|
|
|
@@ -536,7 +537,7 @@ func TestATapIsAcknowledgedWithTheRoutersWordOnIt(t *testing.T) {
|
|
|
|
|
t.Fatalf("the tap was acknowledged before the router said anything: %v", got)
|
|
|
|
|
}
|
|
|
|
|
sentBefore := len(f.of("sendMessage"))
|
|
|
|
|
subject, body := work(channel.Send, channel.Message{Handle: "r1", Title: "You chose Release: recorded, and mesh-delivery was told.",
|
|
|
|
|
subject, body := work(occ.Send, oc.Message{Handle: "r1", Title: "You chose Release: recorded, and mesh-delivery was told.",
|
|
|
|
|
Silent: true, Reply: "tg-tap-cb1", To: "42"})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
@@ -569,7 +570,7 @@ func TestARefusedTapSaysWhyOnThePhoneAndInTheChat(t *testing.T) {
|
|
|
|
|
shown := showQuestion(t, c, f)
|
|
|
|
|
tapOn(c, shown, "cb1")
|
|
|
|
|
sentBefore := len(f.of("sendMessage"))
|
|
|
|
|
subject, body := work(channel.Send, channel.Message{Handle: "r1", Title: "That answer was not taken",
|
|
|
|
|
subject, body := work(occ.Send, oc.Message{Handle: "r1", Title: "That answer was not taken",
|
|
|
|
|
Body: "The question was already answered or has ended. Nothing was done.", Silent: true, Reply: "tg-tap-cb1", To: "42"})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
@@ -595,7 +596,7 @@ func TestATapTheRouterIsSlowOnClaimsNothingAndItsWordComesInTheChat(t *testing.T
|
|
|
|
|
t.Fatalf("a slow router's tap was acknowledged with %v", got)
|
|
|
|
|
}
|
|
|
|
|
sentBefore := len(f.of("sendMessage"))
|
|
|
|
|
subject, body := work(channel.Send, channel.Message{Handle: "r1", Title: "You chose Release: recorded.", Reply: "tg-tap-cb1", To: "42"})
|
|
|
|
|
subject, body := work(occ.Send, oc.Message{Handle: "r1", Title: "You chose Release: recorded.", Reply: "tg-tap-cb1", To: "42"})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
@@ -607,7 +608,7 @@ func TestATapTheRouterIsSlowOnClaimsNothingAndItsWordComesInTheChat(t *testing.T
|
|
|
|
|
return 400, `{"ok":false,"error_code":400,"description":"Bad Request: query is too old and response timeout expired or query ID is invalid"}`
|
|
|
|
|
}
|
|
|
|
|
tapOn(c, shown, "cb2")
|
|
|
|
|
subject, body = work(channel.Send, channel.Message{Handle: "r2", Title: "You chose Release: recorded.", Reply: "tg-tap-cb2", To: "42"})
|
|
|
|
|
subject, body = work(occ.Send, oc.Message{Handle: "r2", Title: "You chose Release: recorded.", Reply: "tg-tap-cb2", To: "42"})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
@@ -629,7 +630,7 @@ func TestATapNotSaidToTheRouterIsSaidSoAndASecretIsNeverAToast(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
c.Publish = func(string, any, string) error { return nil }
|
|
|
|
|
tapOn(c, shown, "cb2")
|
|
|
|
|
subject, body := work(channel.Send, channel.Message{Handle: "r1", Title: "Your code", Body: "123456", Secret: true,
|
|
|
|
|
subject, body := work(occ.Send, oc.Message{Handle: "r1", Title: "Your code", Body: "123456", Secret: true,
|
|
|
|
|
Reply: "tg-tap-cb2", To: "42"})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
@@ -643,11 +644,11 @@ func TestATapNotSaidToTheRouterIsSaidSoAndASecretIsNeverAToast(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
// The toast is the title and the first line of the body, cut at Telegram's bound.
|
|
|
|
|
func TestAToastIsCutAtTelegramsBound(t *testing.T) {
|
|
|
|
|
long := toast(channel.Message{Title: strings.Repeat("a", 300)})
|
|
|
|
|
long := toast(oc.Message{Title: strings.Repeat("a", 300)})
|
|
|
|
|
if utf8.RuneCountInString(long) != ToastLength || !strings.HasSuffix(long, "…") {
|
|
|
|
|
t.Errorf("a long toast is %d runes", utf8.RuneCountInString(long))
|
|
|
|
|
}
|
|
|
|
|
if got := toast(channel.Message{Title: "Details: x", Body: "first\nsecond"}); got != "Details: x: first" {
|
|
|
|
|
if got := toast(oc.Message{Title: "Details: x", Body: "first\nsecond"}); got != "Details: x: first" {
|
|
|
|
|
t.Errorf("toast %q", got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -657,19 +658,19 @@ func TestAToastIsCutAtTelegramsBound(t *testing.T) {
|
|
|
|
|
// loses its buttons. A new handle is a new message, and nothing is deleted.
|
|
|
|
|
func TestAMessageSaidAgainUnderItsHandleReplacesTheEarlierOne(t *testing.T) {
|
|
|
|
|
c, f, _, st := newChannel(t, goodToken)
|
|
|
|
|
subject, body := work(channel.Show, channel.Message{Handle: "m1", Title: "Urgent: ace silent", Urgent: true, To: "42",
|
|
|
|
|
Buttons: []channel.Button{{Label: "Silence for a week", Ticket: "0123456789abcdef0123456789abcdef"}}})
|
|
|
|
|
subject, body := work(occ.Show, oc.Message{Handle: "m1", Title: "Urgent: ace silent", Urgent: true, To: "42",
|
|
|
|
|
Buttons: []oc.Button{{Label: "Silence for a week", Ticket: "0123456789abcdef0123456789abcdef"}}})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
first := st.placed["m1"].ID
|
|
|
|
|
subject, body = work(channel.Send, channel.Message{Handle: "m2", Title: "another problem", To: "42"})
|
|
|
|
|
subject, body = work(occ.Send, oc.Message{Handle: "m2", Title: "another problem", To: "42"})
|
|
|
|
|
_ = c.Take(subject, body)
|
|
|
|
|
if len(f.of("deleteMessage")) != 0 {
|
|
|
|
|
t.Fatal("a new handle deleted a message")
|
|
|
|
|
}
|
|
|
|
|
subject, body = work(channel.Show, channel.Message{Handle: "m1", Title: "Still open: ace silent", Urgent: true, To: "42",
|
|
|
|
|
Buttons: []channel.Button{{Label: "Silence for a week", Ticket: "fedcba9876543210fedcba9876543210"}}})
|
|
|
|
|
subject, body = work(occ.Show, oc.Message{Handle: "m1", Title: "Still open: ace silent", Urgent: true, To: "42",
|
|
|
|
|
Buttons: []oc.Button{{Label: "Silence for a week", Ticket: "fedcba9876543210fedcba9876543210"}}})
|
|
|
|
|
if err := c.Take(subject, body); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
@@ -686,7 +687,7 @@ func TestAMessageSaidAgainUnderItsHandleReplacesTheEarlierOne(t *testing.T) {
|
|
|
|
|
return 400, `{"ok":false,"error_code":400,"description":"Bad Request: message can't be deleted"}`
|
|
|
|
|
}
|
|
|
|
|
second := st.placed["m1"].ID
|
|
|
|
|
subject, body = work(channel.Send, channel.Message{Handle: "m1", Title: "Now urgent: ace silent", Urgent: true, To: "42"})
|
|
|
|
|
subject, body = work(occ.Send, oc.Message{Handle: "m1", Title: "Now urgent: ace silent", Urgent: true, To: "42"})
|
|
|
|
|
_ = c.Take(subject, body)
|
|
|
|
|
ed := f.of("editMessageText")
|
|
|
|
|
if len(ed) != 1 || ed[0].Body["message_id"] != float64(second) || !strings.Contains(ed[0].Body["text"].(string), "Replaced") {
|
|
|
|
@@ -705,7 +706,7 @@ func TestAReplacementThatCannotBeSentLeavesTheEarlierMessage(t *testing.T) {
|
|
|
|
|
f.answer["sendMessage"] = func(map[string]any) (int, string) {
|
|
|
|
|
return 400, `{"ok":false,"error_code":400,"description":"Bad Request: chat not found"}`
|
|
|
|
|
}
|
|
|
|
|
subject, body := work(channel.Send, channel.Message{Handle: "m1", Title: "Still open: ace silent", Urgent: true, To: "42"})
|
|
|
|
|
subject, body := work(occ.Send, oc.Message{Handle: "m1", Title: "Still open: ace silent", Urgent: true, To: "42"})
|
|
|
|
|
_ = c.Take(subject, body)
|
|
|
|
|
if len(f.of("deleteMessage")) != 0 || st.placed["m1"].ID != 7 {
|
|
|
|
|
t.Fatalf("the earlier message was taken away though its replacement was not sent: %+v", f.of("deleteMessage"))
|
|
|
|
|