All checks were successful
CI / test (push) Successful in 54s
CI / build-and-package (amd64, darwin) (push) Successful in 45s
CI / build-and-package (amd64, linux) (push) Successful in 46s
CI / build-and-package (amd64, windows) (push) Successful in 46s
CI / build-and-package (arm64, darwin) (push) Successful in 44s
CI / build-and-package (arm64, linux) (push) Successful in 47s
146 lines
3.4 KiB
Go
146 lines
3.4 KiB
Go
package telegram
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/kamelion/ratatoskr-go/internal/chat"
|
|
)
|
|
|
|
// fakeTG — тестовый сервер, имитирующий Telegram Bot API.
|
|
type fakeTG struct {
|
|
srv *httptest.Server
|
|
mu sync.Mutex
|
|
sent []sendReq
|
|
updCh chan []update // следующая пачка обновлений
|
|
closed bool
|
|
}
|
|
|
|
type sendReq struct {
|
|
ChatID string `json:"chat_id"`
|
|
Text string `json:"text"`
|
|
}
|
|
|
|
func newFakeTG(t *testing.T) *fakeTG {
|
|
t.Helper()
|
|
f := &fakeTG{updCh: make(chan []update, 10)}
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/botTOKEN/sendMessage", func(w http.ResponseWriter, r *http.Request) {
|
|
var req sendReq
|
|
json.NewDecoder(r.Body).Decode(&req)
|
|
f.mu.Lock()
|
|
f.sent = append(f.sent, req)
|
|
f.mu.Unlock()
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]bool{"ok": true})
|
|
})
|
|
mux.HandleFunc("/botTOKEN/getUpdates", func(w http.ResponseWriter, r *http.Request) {
|
|
f.mu.Lock()
|
|
upds := []update{}
|
|
if len(f.updCh) > 0 {
|
|
upds = <-f.updCh
|
|
}
|
|
f.mu.Unlock()
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]any{"ok": true, "result": upds})
|
|
})
|
|
|
|
f.srv = httptest.NewServer(mux)
|
|
t.Cleanup(f.srv.Close)
|
|
return f
|
|
}
|
|
|
|
func (f *fakeTG) push(text string) {
|
|
msg := message{MessageID: int64(len(f.sent) + 1), Text: text}
|
|
msg.Chat.ID = 123
|
|
f.updCh <- []update{{
|
|
UpdateID: int64(len(f.sent) + 1),
|
|
Message: &msg,
|
|
}}
|
|
}
|
|
|
|
func TestSend(t *testing.T) {
|
|
f := newFakeTG(t)
|
|
ch := New("TOKEN", time.Second)
|
|
ch.client = f.srv.Client()
|
|
// подменяем baseURL на тестовый
|
|
ch.apiURL = f.srv.URL + "/bot%s/"
|
|
|
|
err := ch.Send(context.Background(), "tg://123", chat.Message{Text: "hello"})
|
|
if err != nil {
|
|
t.Fatalf("Send: %v", err)
|
|
}
|
|
if len(f.sent) != 1 {
|
|
t.Fatal("не отправлено")
|
|
}
|
|
if f.sent[0].ChatID != "123" {
|
|
t.Errorf("chat_id = %q, want 123 (без префикса tg://)", f.sent[0].ChatID)
|
|
}
|
|
if f.sent[0].Text != "hello" {
|
|
t.Errorf("text = %q", f.sent[0].Text)
|
|
}
|
|
}
|
|
|
|
func TestSendWithOptions(t *testing.T) {
|
|
f := newFakeTG(t)
|
|
ch := New("TOKEN", time.Second)
|
|
ch.client = f.srv.Client()
|
|
ch.apiURL = f.srv.URL + "/bot%s/"
|
|
|
|
err := ch.Send(context.Background(), "tg://123", chat.Message{
|
|
Text: "Выбери:",
|
|
Options: []chat.Option{
|
|
{ID: "a", Label: "Чай"},
|
|
{ID: "b", Label: "Кофе"},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Send: %v", err)
|
|
}
|
|
if !strings.Contains(f.sent[0].Text, "<b>1.</b> Чай") {
|
|
t.Errorf("формат options: %s", f.sent[0].Text)
|
|
}
|
|
if !strings.Contains(f.sent[0].Text, "<b>2.</b> Кофе") {
|
|
t.Errorf("формат options: %s", f.sent[0].Text)
|
|
}
|
|
}
|
|
|
|
func TestIncoming(t *testing.T) {
|
|
f := newFakeTG(t)
|
|
ch := New("TOKEN", time.Second)
|
|
ch.client = f.srv.Client()
|
|
ch.apiURL = f.srv.URL + "/bot%s/"
|
|
|
|
incoming := make(chan chat.Incoming, 1)
|
|
ch.OnMessage(func(inc chat.Incoming) {
|
|
incoming <- inc
|
|
})
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
defer cancel()
|
|
|
|
go ch.Run(ctx)
|
|
|
|
f.push("тест")
|
|
|
|
select {
|
|
case inc := <-incoming:
|
|
if inc.UserID != "123" {
|
|
t.Errorf("UserID = %q, want 123", inc.UserID)
|
|
}
|
|
if inc.Address != "tg://123" {
|
|
t.Errorf("Address = %q", inc.Address)
|
|
}
|
|
if inc.Msg.Text != "тест" {
|
|
t.Errorf("text = %q", inc.Msg.Text)
|
|
}
|
|
case <-ctx.Done():
|
|
t.Fatal("timeout ожидания входящего")
|
|
}
|
|
} |