feat: sync Bot API gateway support
This commit is contained in:
parent
9a501f900a
commit
4c0cc2b7a7
44 changed files with 4609 additions and 49 deletions
|
|
@ -1,8 +1,10 @@
|
|||
package botapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
|
|
@ -129,6 +131,429 @@ func TestAnswerWebAppQueryRejectsUnsupportedResult(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetMeUsesGateway(t *testing.T) {
|
||||
bots := &fakeBotAPIBots{profile: domain.BotProfile{BotUserID: 1001, TokenSecret: "secret"}}
|
||||
gateway := &fakeBotAPIGateway{
|
||||
self: domain.User{ID: 1001, FirstName: "Echo", Username: "echo_bot", Bot: true},
|
||||
}
|
||||
h := (&handler{bots: bots, gateway: gateway}).routes()
|
||||
|
||||
rec := performBotAPIRequest(t, h, bots.profile, "getMe", `{}`)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d body = %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
var resp struct {
|
||||
OK bool `json:"ok"`
|
||||
Result struct {
|
||||
ID int64 `json:"id"`
|
||||
IsBot bool `json:"is_bot"`
|
||||
FirstName string `json:"first_name"`
|
||||
Username string `json:"username"`
|
||||
} `json:"result"`
|
||||
}
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if !resp.OK || resp.Result.ID != 1001 || !resp.Result.IsBot || resp.Result.Username != "echo_bot" {
|
||||
t.Fatalf("response = %s", rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUpdatesProjectsIncomingPrivateText(t *testing.T) {
|
||||
bots := &fakeBotAPIBots{profile: domain.BotProfile{BotUserID: 1001, TokenSecret: "secret"}}
|
||||
gateway := &fakeBotAPIGateway{
|
||||
updates: []domain.UpdateEvent{{
|
||||
UserID: 1001,
|
||||
Type: domain.UpdateEventNewMessage,
|
||||
Pts: 7,
|
||||
Message: domain.Message{
|
||||
ID: 3,
|
||||
OwnerUserID: 1001,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 2001},
|
||||
From: domain.Peer{Type: domain.PeerTypeUser, ID: 2001},
|
||||
Date: 1700000000,
|
||||
Body: "/start",
|
||||
Entities: []domain.MessageEntity{{Type: domain.MessageEntityBotCommand, Offset: 0, Length: 6}},
|
||||
},
|
||||
Users: []domain.User{{ID: 2001, FirstName: "Alice", Username: "alice"}},
|
||||
}},
|
||||
}
|
||||
h := (&handler{bots: bots, gateway: gateway}).routes()
|
||||
|
||||
rec := performBotAPIRequest(t, h, bots.profile, "getUpdates", `{"offset":1,"allowed_updates":["message"]}`)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d body = %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
var resp struct {
|
||||
OK bool `json:"ok"`
|
||||
Result []struct {
|
||||
UpdateID int `json:"update_id"`
|
||||
Message struct {
|
||||
MessageID int `json:"message_id"`
|
||||
Text string `json:"text"`
|
||||
From struct {
|
||||
ID int64 `json:"id"`
|
||||
FirstName string `json:"first_name"`
|
||||
} `json:"from"`
|
||||
Chat struct {
|
||||
ID int64 `json:"id"`
|
||||
Type string `json:"type"`
|
||||
} `json:"chat"`
|
||||
Entities []struct {
|
||||
Type string `json:"type"`
|
||||
Offset int `json:"offset"`
|
||||
Length int `json:"length"`
|
||||
} `json:"entities"`
|
||||
} `json:"message"`
|
||||
} `json:"result"`
|
||||
}
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if !resp.OK || len(resp.Result) != 1 {
|
||||
t.Fatalf("response = %s", rec.Body.String())
|
||||
}
|
||||
got := resp.Result[0]
|
||||
if got.UpdateID != 7 || got.Message.MessageID != 3 || got.Message.Text != "/start" || got.Message.From.ID != 2001 || got.Message.Chat.ID != 2001 || got.Message.Chat.Type != "private" {
|
||||
t.Fatalf("update = %#v", got)
|
||||
}
|
||||
if len(got.Message.Entities) != 1 || got.Message.Entities[0].Type != "bot_command" {
|
||||
t.Fatalf("entities = %#v", got.Message.Entities)
|
||||
}
|
||||
if gateway.updateOffset != 1 {
|
||||
t.Fatalf("offset = %d, want 1", gateway.updateOffset)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUpdatesSkipsOutgoingBotMessage(t *testing.T) {
|
||||
bots := &fakeBotAPIBots{profile: domain.BotProfile{BotUserID: 1001, TokenSecret: "secret"}}
|
||||
gateway := &fakeBotAPIGateway{
|
||||
updates: []domain.UpdateEvent{{
|
||||
UserID: 1001,
|
||||
Type: domain.UpdateEventNewMessage,
|
||||
Pts: 8,
|
||||
Message: domain.Message{
|
||||
ID: 4,
|
||||
OwnerUserID: 1001,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 2001},
|
||||
From: domain.Peer{Type: domain.PeerTypeUser, ID: 1001},
|
||||
Date: 1700000001,
|
||||
Body: "sent by bot",
|
||||
Out: true,
|
||||
},
|
||||
}},
|
||||
}
|
||||
h := (&handler{bots: bots, gateway: gateway}).routes()
|
||||
|
||||
rec := performBotAPIRequest(t, h, bots.profile, "getUpdates", `{}`)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d body = %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
var resp struct {
|
||||
OK bool `json:"ok"`
|
||||
Result []json.RawMessage `json:"result"`
|
||||
}
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if !resp.OK || len(resp.Result) != 0 {
|
||||
t.Fatalf("response = %s", rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendMessageParsesEntitiesMarkupAndCallsGateway(t *testing.T) {
|
||||
bots := &fakeBotAPIBots{profile: domain.BotProfile{BotUserID: 1001, TokenSecret: "secret"}}
|
||||
gateway := &fakeBotAPIGateway{
|
||||
self: domain.User{ID: 1001, FirstName: "Echo", Username: "echo_bot", Bot: true},
|
||||
sendMessage: domain.Message{
|
||||
ID: 9,
|
||||
OwnerUserID: 1001,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 2001},
|
||||
From: domain.Peer{Type: domain.PeerTypeUser, ID: 1001},
|
||||
Date: 1700000002,
|
||||
Body: "hello",
|
||||
Out: true,
|
||||
Entities: []domain.MessageEntity{{Type: domain.MessageEntityBold, Offset: 0, Length: 5}},
|
||||
ReplyMarkup: &domain.MessageReplyMarkup{Inline: [][]domain.MarkupButton{{{Type: domain.MarkupButtonCallback, Text: "Tap", Data: []byte("cb")}}}},
|
||||
},
|
||||
}
|
||||
h := (&handler{bots: bots, gateway: gateway}).routes()
|
||||
body := `{
|
||||
"chat_id": 2001,
|
||||
"text": "hello",
|
||||
"entities": [{"type":"bold","offset":0,"length":5}],
|
||||
"reply_markup": {"inline_keyboard": [[{"text":"Tap","callback_data":"cb"}]]},
|
||||
"disable_notification": true,
|
||||
"reply_to_message_id": 5
|
||||
}`
|
||||
|
||||
rec := performBotAPIRequest(t, h, bots.profile, "sendMessage", body)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d body = %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if !gateway.sendCalled || gateway.sendBotID != 1001 || gateway.sendChatID != 2001 || gateway.sendText != "hello" || !gateway.sendSilent || gateway.sendReplyTo != 5 {
|
||||
t.Fatalf("send call = %#v", gateway)
|
||||
}
|
||||
if len(gateway.sendEntities) != 1 || gateway.sendEntities[0].Type != domain.MessageEntityBold {
|
||||
t.Fatalf("entities = %#v", gateway.sendEntities)
|
||||
}
|
||||
if gateway.sendMarkup == nil || len(gateway.sendMarkup.Inline) != 1 || len(gateway.sendMarkup.Inline[0]) != 1 || string(gateway.sendMarkup.Inline[0][0].Data) != "cb" {
|
||||
t.Fatalf("markup = %#v", gateway.sendMarkup)
|
||||
}
|
||||
var resp struct {
|
||||
OK bool `json:"ok"`
|
||||
Result struct {
|
||||
MessageID int `json:"message_id"`
|
||||
Text string `json:"text"`
|
||||
From struct {
|
||||
ID int64 `json:"id"`
|
||||
IsBot bool `json:"is_bot"`
|
||||
} `json:"from"`
|
||||
ReplyMarkup struct {
|
||||
InlineKeyboard [][]struct {
|
||||
Text string `json:"text"`
|
||||
CallbackData string `json:"callback_data"`
|
||||
} `json:"inline_keyboard"`
|
||||
} `json:"reply_markup"`
|
||||
} `json:"result"`
|
||||
}
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if !resp.OK || resp.Result.MessageID != 9 || resp.Result.Text != "hello" || resp.Result.From.ID != 1001 || !resp.Result.From.IsBot {
|
||||
t.Fatalf("response = %s", rec.Body.String())
|
||||
}
|
||||
if len(resp.Result.ReplyMarkup.InlineKeyboard) != 1 || resp.Result.ReplyMarkup.InlineKeyboard[0][0].CallbackData != "cb" {
|
||||
t.Fatalf("reply_markup response = %#v", resp.Result.ReplyMarkup)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendDocumentMultipartParsesFileAndCaption(t *testing.T) {
|
||||
bots := &fakeBotAPIBots{profile: domain.BotProfile{BotUserID: 1001, TokenSecret: "secret"}}
|
||||
gateway := &fakeBotAPIGateway{
|
||||
self: domain.User{ID: 1001, FirstName: "Echo", Username: "echo_bot", Bot: true},
|
||||
sendMediaMessage: domain.Message{
|
||||
ID: 11,
|
||||
OwnerUserID: 1001,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 2001},
|
||||
From: domain.Peer{Type: domain.PeerTypeUser, ID: 1001},
|
||||
Date: 1700000006,
|
||||
Body: "doc caption",
|
||||
Out: true,
|
||||
Media: &domain.MessageMedia{
|
||||
Kind: domain.MessageMediaKindDocument,
|
||||
Document: &domain.Document{
|
||||
ID: 42,
|
||||
MimeType: "text/plain",
|
||||
Size: 10,
|
||||
Attributes: []domain.DocumentAttribute{{
|
||||
Kind: domain.DocAttrFilename,
|
||||
FileName: "note.txt",
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h := (&handler{bots: bots, gateway: gateway}).routes()
|
||||
|
||||
var body bytes.Buffer
|
||||
writer := multipart.NewWriter(&body)
|
||||
_ = writer.WriteField("chat_id", "2001")
|
||||
_ = writer.WriteField("caption", "doc caption")
|
||||
part, err := writer.CreateFormFile("document", "note.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("create form file: %v", err)
|
||||
}
|
||||
if _, err := part.Write([]byte("hello file")); err != nil {
|
||||
t.Fatalf("write file: %v", err)
|
||||
}
|
||||
if err := writer.Close(); err != nil {
|
||||
t.Fatalf("close multipart: %v", err)
|
||||
}
|
||||
token := domain.FormatBotToken(bots.profile.BotUserID, bots.profile.TokenSecret)
|
||||
req := httptest.NewRequest(http.MethodPost, "/bot"+token+"/sendDocument", &body)
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d body = %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if !gateway.sendMediaCalled || gateway.sendMediaKind != "document" || gateway.sendMediaChatID != 2001 || gateway.sendMediaCaption != "doc caption" {
|
||||
t.Fatalf("send media call = %#v", gateway)
|
||||
}
|
||||
if gateway.sendMediaFileName != "note.txt" || string(gateway.sendMediaBytes) != "hello file" {
|
||||
t.Fatalf("file = name %q bytes %q", gateway.sendMediaFileName, string(gateway.sendMediaBytes))
|
||||
}
|
||||
var resp struct {
|
||||
OK bool `json:"ok"`
|
||||
Result struct {
|
||||
Caption string `json:"caption"`
|
||||
Document struct {
|
||||
FileName string `json:"file_name"`
|
||||
FileID string `json:"file_id"`
|
||||
} `json:"document"`
|
||||
} `json:"result"`
|
||||
}
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if !resp.OK || resp.Result.Caption != "doc caption" || resp.Result.Document.FileName != "note.txt" {
|
||||
t.Fatalf("response = %s", rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestEditDeleteCallbackAndFileEndpoints(t *testing.T) {
|
||||
bots := &fakeBotAPIBots{profile: domain.BotProfile{BotUserID: 1001, TokenSecret: "secret"}}
|
||||
locationKey := "doc:42"
|
||||
fileID := encodeBotAPIFileID(locationKey)
|
||||
gateway := &fakeBotAPIGateway{
|
||||
self: domain.User{ID: 1001, FirstName: "Echo", Username: "echo_bot", Bot: true},
|
||||
editMessage: domain.Message{
|
||||
ID: 9,
|
||||
OwnerUserID: 1001,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 2001},
|
||||
From: domain.Peer{Type: domain.PeerTypeUser, ID: 1001},
|
||||
Date: 1700000003,
|
||||
EditDate: 1700000004,
|
||||
Body: "edited",
|
||||
Out: true,
|
||||
},
|
||||
fileChunks: map[string]domain.FileChunk{
|
||||
locationKey: {Bytes: []byte("hello file"), MimeType: "text/plain", Total: int64(len("hello file"))},
|
||||
},
|
||||
}
|
||||
h := (&handler{bots: bots, gateway: gateway}).routes()
|
||||
|
||||
edit := performBotAPIRequest(t, h, bots.profile, "editMessageText", `{"chat_id":2001,"message_id":9,"text":"edited","reply_markup":{"inline_keyboard":[]}}`)
|
||||
if edit.Code != http.StatusOK {
|
||||
t.Fatalf("edit status = %d body = %s", edit.Code, edit.Body.String())
|
||||
}
|
||||
if !gateway.editCalled || !gateway.editSetMarkup {
|
||||
t.Fatalf("edit gateway = %#v", gateway)
|
||||
}
|
||||
|
||||
del := performBotAPIRequest(t, h, bots.profile, "deleteMessage", `{"chat_id":2001,"message_id":9}`)
|
||||
if del.Code != http.StatusOK || !gateway.deleteCalled {
|
||||
t.Fatalf("delete status = %d body = %s gateway=%#v", del.Code, del.Body.String(), gateway)
|
||||
}
|
||||
|
||||
cb := performBotAPIRequest(t, h, bots.profile, "answerCallbackQuery", `{"callback_query_id":"123","text":"ok"}`)
|
||||
if cb.Code != http.StatusOK || !gateway.callbackCalled || gateway.callbackID != "123" {
|
||||
t.Fatalf("callback status = %d body = %s gateway=%#v", cb.Code, cb.Body.String(), gateway)
|
||||
}
|
||||
|
||||
file := performBotAPIRequest(t, h, bots.profile, "getFile", `{"file_id":"`+fileID+`"}`)
|
||||
if file.Code != http.StatusOK {
|
||||
t.Fatalf("getFile status = %d body = %s", file.Code, file.Body.String())
|
||||
}
|
||||
var fileResp struct {
|
||||
OK bool `json:"ok"`
|
||||
Result struct {
|
||||
FileID string `json:"file_id"`
|
||||
FilePath string `json:"file_path"`
|
||||
FileSize int64 `json:"file_size"`
|
||||
} `json:"result"`
|
||||
}
|
||||
if err := json.Unmarshal(file.Body.Bytes(), &fileResp); err != nil {
|
||||
t.Fatalf("decode getFile: %v", err)
|
||||
}
|
||||
if !fileResp.OK || fileResp.Result.FileID != fileID || fileResp.Result.FilePath != fileID || fileResp.Result.FileSize != int64(len("hello file")) || gateway.fileLocationKey != locationKey {
|
||||
t.Fatalf("getFile response = %s gateway=%#v", file.Body.String(), gateway)
|
||||
}
|
||||
|
||||
token := domain.FormatBotToken(bots.profile.BotUserID, bots.profile.TokenSecret)
|
||||
req := httptest.NewRequest(http.MethodGet, "/file/bot"+token+"/"+fileID, nil)
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusOK || rec.Body.String() != "hello file" || rec.Header().Get("Content-Type") != "text/plain" {
|
||||
t.Fatalf("download status=%d content-type=%q body=%q", rec.Code, rec.Header().Get("Content-Type"), rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIMessageProjectsMediaCaptionAndFileID(t *testing.T) {
|
||||
msg := domain.Message{
|
||||
ID: 3,
|
||||
OwnerUserID: 1001,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 2001},
|
||||
From: domain.Peer{Type: domain.PeerTypeUser, ID: 2001},
|
||||
Date: 1700000005,
|
||||
Body: "caption",
|
||||
Entities: []domain.MessageEntity{{Type: domain.MessageEntityBold, Offset: 0, Length: 7}},
|
||||
Media: &domain.MessageMedia{
|
||||
Kind: domain.MessageMediaKindDocument,
|
||||
Document: &domain.Document{
|
||||
ID: 42,
|
||||
MimeType: "text/plain",
|
||||
Size: 10,
|
||||
Attributes: []domain.DocumentAttribute{{
|
||||
Kind: domain.DocAttrFilename,
|
||||
FileName: "note.txt",
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
projected := apiMessage(msg, []domain.User{{ID: 2001, FirstName: "Alice"}})
|
||||
if _, hasText := projected["text"]; hasText {
|
||||
t.Fatalf("media message has text field: %#v", projected)
|
||||
}
|
||||
if projected["caption"] != "caption" {
|
||||
t.Fatalf("caption = %#v", projected["caption"])
|
||||
}
|
||||
if _, ok := projected["caption_entities"].([]map[string]any); !ok {
|
||||
t.Fatalf("caption_entities = %#v", projected["caption_entities"])
|
||||
}
|
||||
document, ok := projected["document"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("document = %#v", projected["document"])
|
||||
}
|
||||
fileID, _ := document["file_id"].(string)
|
||||
if locationKey, ok := decodeBotAPIFileID(fileID); !ok || locationKey != "doc:42" {
|
||||
t.Fatalf("file_id %q decodes to %q ok=%v", fileID, locationKey, ok)
|
||||
}
|
||||
if document["file_name"] != "note.txt" || document["mime_type"] != "text/plain" {
|
||||
t.Fatalf("document = %#v", document)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIUpdateProjectsCaptionlessMediaMessage(t *testing.T) {
|
||||
item, kind, ok := apiUpdate(domain.UpdateEvent{
|
||||
Type: domain.UpdateEventNewMessage,
|
||||
Pts: 12,
|
||||
Message: domain.Message{
|
||||
ID: 4,
|
||||
OwnerUserID: 1001,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 2001},
|
||||
From: domain.Peer{Type: domain.PeerTypeUser, ID: 2001},
|
||||
Date: 1700000006,
|
||||
Media: &domain.MessageMedia{
|
||||
Kind: domain.MessageMediaKindDocument,
|
||||
Document: &domain.Document{
|
||||
ID: 43,
|
||||
MimeType: "application/octet-stream",
|
||||
Size: 4,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if !ok || kind != "message" {
|
||||
t.Fatalf("apiUpdate ok=%v kind=%q item=%#v", ok, kind, item)
|
||||
}
|
||||
msg, ok := item["message"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("message = %#v", item["message"])
|
||||
}
|
||||
if _, hasText := msg["text"]; hasText {
|
||||
t.Fatalf("captionless media has text: %#v", msg)
|
||||
}
|
||||
if _, hasCaption := msg["caption"]; hasCaption {
|
||||
t.Fatalf("captionless media has caption: %#v", msg)
|
||||
}
|
||||
if _, ok := msg["document"].(map[string]any); !ok {
|
||||
t.Fatalf("document = %#v", msg["document"])
|
||||
}
|
||||
}
|
||||
|
||||
func performBotAPIRequest(t *testing.T, h http.Handler, profile domain.BotProfile, method, body string) *httptest.ResponseRecorder {
|
||||
t.Helper()
|
||||
token := domain.FormatBotToken(profile.BotUserID, profile.TokenSecret)
|
||||
|
|
@ -196,3 +621,105 @@ func (f *fakeWebAppService) SavePreparedInlineMessageFromBotAPI(_ context.Contex
|
|||
f.preparedPeerTypes = append([]string(nil), peerTypes...)
|
||||
return f.preparedID, f.preparedExpire, nil
|
||||
}
|
||||
|
||||
type fakeBotAPIGateway struct {
|
||||
self domain.User
|
||||
|
||||
updates []domain.UpdateEvent
|
||||
updateBotID int64
|
||||
updateOffset int64
|
||||
|
||||
sendCalled bool
|
||||
sendBotID int64
|
||||
sendChatID int64
|
||||
sendText string
|
||||
sendEntities []domain.MessageEntity
|
||||
sendMarkup *domain.MessageReplyMarkup
|
||||
sendNoWebpage bool
|
||||
sendSilent bool
|
||||
sendReplyTo int
|
||||
sendMessage domain.Message
|
||||
sendMediaCalled bool
|
||||
sendMediaKind string
|
||||
sendMediaChatID int64
|
||||
sendMediaFileName string
|
||||
sendMediaBytes []byte
|
||||
sendMediaCaption string
|
||||
sendMediaMessage domain.Message
|
||||
editCalled bool
|
||||
editSetMarkup bool
|
||||
editMessage domain.Message
|
||||
deleteCalled bool
|
||||
callbackCalled bool
|
||||
callbackID string
|
||||
fileLocationKey string
|
||||
fileChunks map[string]domain.FileChunk
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPISelf(context.Context, int64) (domain.User, error) {
|
||||
return f.self, nil
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPIUpdates(_ context.Context, botID int64, offset int64) ([]domain.UpdateEvent, error) {
|
||||
f.updateBotID = botID
|
||||
f.updateOffset = offset
|
||||
return append([]domain.UpdateEvent(nil), f.updates...), nil
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPISendMessage(_ context.Context, botID, chatID int64, text string, entities []domain.MessageEntity, replyMarkup *domain.MessageReplyMarkup, disableWebPagePreview, silent bool, replyToMessageID int) (domain.Message, error) {
|
||||
f.sendCalled = true
|
||||
f.sendBotID = botID
|
||||
f.sendChatID = chatID
|
||||
f.sendText = text
|
||||
f.sendEntities = append([]domain.MessageEntity(nil), entities...)
|
||||
f.sendMarkup = replyMarkup
|
||||
f.sendNoWebpage = disableWebPagePreview
|
||||
f.sendSilent = silent
|
||||
f.sendReplyTo = replyToMessageID
|
||||
return f.sendMessage, nil
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPISendMedia(_ context.Context, botID, chatID int64, kind, locationKey, remoteURL, fileName, mimeType string, fileBytes []byte, caption string, entities []domain.MessageEntity, replyMarkup *domain.MessageReplyMarkup, silent bool, replyToMessageID int) (domain.Message, error) {
|
||||
f.sendMediaCalled = true
|
||||
f.sendMediaKind = kind
|
||||
f.sendMediaChatID = chatID
|
||||
f.sendMediaFileName = fileName
|
||||
f.sendMediaBytes = append([]byte(nil), fileBytes...)
|
||||
f.sendMediaCaption = caption
|
||||
return f.sendMediaMessage, nil
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPIEditMessageText(_ context.Context, botID, chatID int64, messageID int, text string, entities []domain.MessageEntity, setReplyMarkup bool, replyMarkup *domain.MessageReplyMarkup, disableWebPagePreview bool) (domain.Message, error) {
|
||||
f.editCalled = true
|
||||
f.editSetMarkup = setReplyMarkup
|
||||
return f.editMessage, nil
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPIDeleteMessage(context.Context, int64, int64, int) (bool, error) {
|
||||
f.deleteCalled = true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPIAnswerCallbackQuery(_ context.Context, _ int64, callbackQueryID, text, url string, showAlert bool, cacheTime int) (bool, error) {
|
||||
f.callbackCalled = true
|
||||
f.callbackID = callbackQueryID
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPIGetFile(_ context.Context, _ int64, locationKey string, offset int64, limit int) (domain.FileChunk, bool, error) {
|
||||
f.fileLocationKey = locationKey
|
||||
chunk, ok := f.fileChunks[locationKey]
|
||||
if !ok {
|
||||
return domain.FileChunk{}, false, nil
|
||||
}
|
||||
if offset >= int64(len(chunk.Bytes)) {
|
||||
return domain.FileChunk{MimeType: chunk.MimeType, Total: chunk.Total}, true, nil
|
||||
}
|
||||
end := offset + int64(limit)
|
||||
if end > int64(len(chunk.Bytes)) {
|
||||
end = int64(len(chunk.Bytes))
|
||||
}
|
||||
out := chunk
|
||||
out.Bytes = append([]byte(nil), chunk.Bytes[offset:end]...)
|
||||
return out, true, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue