mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-29 11:36:36 +08:00
234 lines
6.8 KiB
Go
234 lines
6.8 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ShukeBta/MediaStationGo/internal/model"
|
|
)
|
|
|
|
func TestTelegramMethodURLUsesCustomAPIBase(t *testing.T) {
|
|
got, err := telegramMethodURL(map[string]string{
|
|
"api_base_url": "https://tg.example.com/",
|
|
}, "123456:ABC-def", "sendMessage")
|
|
if err != nil {
|
|
t.Fatalf("telegramMethodURL returned error: %v", err)
|
|
}
|
|
want := "https://tg.example.com/bot123456:ABC-def/sendMessage"
|
|
if got != want {
|
|
t.Fatalf("got %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeTelegramErrorRedactsBotToken(t *testing.T) {
|
|
err := sanitizeTelegramError(errors.New(`Post "https://api.telegram.org/bot123456:SECRET/sendMessage": context deadline exceeded`))
|
|
if err == nil {
|
|
t.Fatal("expected error")
|
|
}
|
|
msg := err.Error()
|
|
if strings.Contains(msg, "SECRET") || strings.Contains(msg, "123456:") {
|
|
t.Fatalf("telegram token leaked in error: %s", msg)
|
|
}
|
|
if !strings.Contains(msg, "timeout") {
|
|
t.Fatalf("expected timeout hint, got: %s", msg)
|
|
}
|
|
}
|
|
|
|
func TestValidateTelegramChannelDoesNotRequireLegacyChatID(t *testing.T) {
|
|
err := validateChannel(ChannelInput{
|
|
Name: "Telegram",
|
|
Type: "telegram",
|
|
Config: map[string]any{
|
|
"bot_token": "123456:ABC-def",
|
|
"admin_user_ids": "10001",
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("validateChannel returned error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestTelegramTargetChatIDsFallsBackToAdmins(t *testing.T) {
|
|
got := telegramTargetChatIDs(map[string]string{
|
|
"admin_user_ids": "10001, 10002",
|
|
})
|
|
if len(got) != 2 || got[0] != "10001" || got[1] != "10002" {
|
|
t.Fatalf("got %#v, want admin user ids", got)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeTelegramChannelMigratesLegacyChatID(t *testing.T) {
|
|
input := ChannelInput{
|
|
Name: "Telegram",
|
|
Type: "telegram",
|
|
Config: map[string]any{
|
|
"chat_id": "-10001",
|
|
},
|
|
}
|
|
normalizeChannelInput(&input)
|
|
if got := str(input.Config["group_chat_id"]); got != "-10001" {
|
|
t.Fatalf("group_chat_id = %q, want -10001", got)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeTelegramChannelMigratesLegacyPrivateChatIDToAdmin(t *testing.T) {
|
|
cfg := map[string]string{"chat_id": "5812333517"}
|
|
normalizeTelegramConfig(cfg)
|
|
if got := cfg["admin_user_ids"]; got != "5812333517" {
|
|
t.Fatalf("admin_user_ids = %q, want legacy chat_id", got)
|
|
}
|
|
}
|
|
|
|
func TestTelegramTargetChatIDsUsesLegacyPrivateChatID(t *testing.T) {
|
|
got := telegramTargetChatIDs(map[string]string{
|
|
"chat_id": "5812333517",
|
|
})
|
|
if len(got) != 1 || got[0] != "5812333517" {
|
|
t.Fatalf("got %#v, want legacy private chat target", got)
|
|
}
|
|
}
|
|
|
|
func TestRegisterTelegramBotCommands(t *testing.T) {
|
|
var gotPath string
|
|
var payload struct {
|
|
Commands []telegramBotCommand `json:"commands"`
|
|
}
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
gotPath = r.URL.Path
|
|
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
|
t.Fatalf("decode payload: %v", err)
|
|
}
|
|
_, _ = w.Write([]byte(`{"ok":true}`))
|
|
}))
|
|
defer server.Close()
|
|
|
|
err := registerTelegramBotCommands(t.Context(), map[string]string{
|
|
"bot_token": "123456:ABC",
|
|
"api_base_url": server.URL,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if gotPath != "/bot123456:ABC/setMyCommands" {
|
|
t.Fatalf("path = %q", gotPath)
|
|
}
|
|
if len(payload.Commands) == 0 || payload.Commands[0].Command != "start" {
|
|
t.Fatalf("commands not registered: %#v", payload.Commands)
|
|
}
|
|
}
|
|
|
|
func TestTelegramProxyCandidatesDefaultLocalFallbacks(t *testing.T) {
|
|
got := telegramProxyCandidates(map[string]string{})
|
|
joined := strings.Join(got, ",")
|
|
for _, want := range []string{"host.docker.internal:20171", "socks5://172.17.0.1:20170", "127.0.0.1:10808", "172.17.0.1:7890"} {
|
|
if !strings.Contains(joined, want) {
|
|
t.Fatalf("default proxy candidates %q missing %q", joined, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTelegramHTTPClientsPreferConfiguredProxy(t *testing.T) {
|
|
clients := telegramHTTPClients(time.Second, map[string]string{
|
|
"proxy_url": "http://proxy.example:7890",
|
|
})
|
|
if len(clients) == 0 {
|
|
t.Fatal("expected telegram clients")
|
|
}
|
|
if got := telegramClientProxyString(t, clients[0]); got != "http://proxy.example:7890" {
|
|
t.Fatalf("first client proxy = %q, want configured proxy", got)
|
|
}
|
|
}
|
|
|
|
func telegramClientProxyString(t *testing.T, client *http.Client) string {
|
|
t.Helper()
|
|
transport, ok := client.Transport.(*http.Transport)
|
|
if !ok || transport.Proxy == nil {
|
|
return ""
|
|
}
|
|
req, err := http.NewRequest(http.MethodGet, defaultTelegramAPIBaseURL, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
proxyURL, err := transport.Proxy(req)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if proxyURL == nil {
|
|
return ""
|
|
}
|
|
return proxyURL.String()
|
|
}
|
|
|
|
func TestTelegramReplyAutoDeletesSentMessage(t *testing.T) {
|
|
requests := make(chan string, 4)
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch {
|
|
case strings.HasSuffix(r.URL.Path, "/sendMessage"):
|
|
requests <- "sendMessage"
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write([]byte(`{"ok":true,"result":{"message_id":777}}`))
|
|
case strings.HasSuffix(r.URL.Path, "/deleteMessage"):
|
|
requests <- "deleteMessage"
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write([]byte(`{"ok":true,"result":true}`))
|
|
default:
|
|
http.NotFound(w, r)
|
|
}
|
|
}))
|
|
defer server.Close()
|
|
|
|
cfg, _ := json.Marshal(map[string]string{
|
|
"bot_token": "123456:ABC-def",
|
|
"api_base_url": server.URL,
|
|
"auto_delete_seconds": "0",
|
|
})
|
|
_, bot := newBotTestService(t)
|
|
channel := &model.NotifyChannel{Name: "Telegram", Type: "telegram", Enabled: true, Config: string(cfg)}
|
|
if err := bot.reply(context.Background(), channel, 42, telegramCommandReply{Text: "hello"}); err != nil {
|
|
t.Fatalf("reply: %v", err)
|
|
}
|
|
waitForTelegramMethod(t, requests, "sendMessage")
|
|
waitForTelegramMethod(t, requests, "deleteMessage")
|
|
}
|
|
|
|
func waitForTelegramMethod(t *testing.T, requests <-chan string, want string) {
|
|
t.Helper()
|
|
deadline := time.After(2 * time.Second)
|
|
for {
|
|
select {
|
|
case got := <-requests:
|
|
if got == want {
|
|
return
|
|
}
|
|
case <-deadline:
|
|
t.Fatalf("timed out waiting for telegram %s", want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTelegramCommandFiltering(t *testing.T) {
|
|
if telegramIsCommandText("今天看什么") {
|
|
t.Fatal("plain chat message should not be treated as command")
|
|
}
|
|
if !telegramIsCommandText("/start user pass") {
|
|
t.Fatal("/start should be treated as command")
|
|
}
|
|
if got := telegramCommandName("/hideadult@MediaStationGoBot on"); got != "/hideadult" {
|
|
t.Fatalf("telegramCommandName = %q, want /hideadult", got)
|
|
}
|
|
if telegramSupportedCommand("/签到") {
|
|
t.Fatal("unrelated group bot command should not be handled")
|
|
}
|
|
for _, cmd := range []string{"/signin", "/redeem", "/gencode", "/users", "/renew_user", "/delete_user", "/cleanup_rule"} {
|
|
if !telegramSupportedCommand(cmd) {
|
|
t.Fatalf("%s should be supported so group slash commands get feedback", cmd)
|
|
}
|
|
}
|
|
}
|