mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-29 19:36:36 +08:00
fix subscription dedup progress tracking
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
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 TestTelegramGroupCommandSendsPanelInGroup(t *testing.T) {
|
||||
var payloads []struct {
|
||||
ChatID any `json:"chat_id"`
|
||||
Text string `json:"text"`
|
||||
ReplyMarkup map[string]any `json:"reply_markup"`
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.HasSuffix(r.URL.Path, "/sendMessage") {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
var payload struct {
|
||||
ChatID any `json:"chat_id"`
|
||||
Text string `json:"text"`
|
||||
ReplyMarkup map[string]any `json:"reply_markup"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
||||
t.Fatalf("decode sendMessage: %v", err)
|
||||
}
|
||||
payloads = append(payloads, payload)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"ok":true,"result":{"message_id":777}}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
repos, bot := newBotTestService(t)
|
||||
cfg, _ := json.Marshal(map[string]string{
|
||||
"bot_token": "123456:ABC-def",
|
||||
"api_base_url": server.URL,
|
||||
"group_chat_id": "-100123",
|
||||
"auto_delete_seconds": "-1",
|
||||
})
|
||||
if err := repos.DB.Create(&model.NotifyChannel{Name: "Telegram", Type: "telegram", Enabled: true, Config: string(cfg)}).Error; err != nil {
|
||||
t.Fatalf("create channel: %v", err)
|
||||
}
|
||||
update, _ := json.Marshal(TelegramUpdate{
|
||||
UpdateID: 1,
|
||||
Message: &TelegramMessage{
|
||||
MessageID: 55,
|
||||
From: TelegramUser{ID: 9002, Username: "viewer", FirstName: "Viewer"},
|
||||
Chat: TelegramChat{ID: -100123, Type: "supergroup"},
|
||||
Text: "/menu",
|
||||
},
|
||||
})
|
||||
if err := bot.HandleWebhook(t.Context(), update); err != nil {
|
||||
t.Fatalf("handle webhook: %v", err)
|
||||
}
|
||||
if len(payloads) != 1 {
|
||||
t.Fatalf("sendMessage count = %d, payloads=%#v", len(payloads), payloads)
|
||||
}
|
||||
if got := fmt.Sprint(payloads[0].ChatID); got != "-100123" {
|
||||
t.Fatalf("message should stay in group, chat_id=%s payload=%#v", got, payloads[0])
|
||||
}
|
||||
if strings.Contains(payloads[0].Text, "管理员入口") {
|
||||
t.Fatalf("normal group user must not see admin panel: %#v", payloads[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestTelegramGroupCallbackIsRejected(t *testing.T) {
|
||||
var callbackPayloads []struct {
|
||||
CallbackID string `json:"callback_query_id"`
|
||||
Text string `json:"text"`
|
||||
ShowAlert bool `json:"show_alert"`
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.HasSuffix(r.URL.Path, "/answerCallbackQuery") {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
var payload struct {
|
||||
CallbackID string `json:"callback_query_id"`
|
||||
Text string `json:"text"`
|
||||
ShowAlert bool `json:"show_alert"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
||||
t.Fatalf("decode answerCallbackQuery: %v", err)
|
||||
}
|
||||
callbackPayloads = append(callbackPayloads, payload)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"ok":true,"result":true}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
ctx := t.Context()
|
||||
repos, auth, _, _ := newAuthTestServices(t)
|
||||
user, _, err := auth.Register(ctx, "viewer", "secret-pass")
|
||||
if err != nil {
|
||||
t.Fatalf("register user: %v", err)
|
||||
}
|
||||
if err := repos.DB.AutoMigrate(&model.NotifyChannel{}); err != nil {
|
||||
t.Fatalf("migrate notify channel: %v", err)
|
||||
}
|
||||
if err := repos.DB.Create(&model.TelegramBinding{
|
||||
TelegramUserID: 9002,
|
||||
TelegramName: "@viewer",
|
||||
ChatID: 9002,
|
||||
UserID: user.ID,
|
||||
}).Error; err != nil {
|
||||
t.Fatalf("create binding: %v", err)
|
||||
}
|
||||
cfg, _ := json.Marshal(map[string]string{
|
||||
"bot_token": "123456:ABC-def",
|
||||
"api_base_url": server.URL,
|
||||
"group_chat_id": "-100123",
|
||||
"auto_delete_seconds": "-1",
|
||||
})
|
||||
if err := repos.DB.Create(&model.NotifyChannel{Name: "Telegram", Type: "telegram", Enabled: true, Config: string(cfg)}).Error; err != nil {
|
||||
t.Fatalf("create channel: %v", err)
|
||||
}
|
||||
before, _ := repos.User.FindByID(ctx, user.ID)
|
||||
bot := NewTelegramBotService(zap.NewNop(), repos, nil, auth)
|
||||
update, _ := json.Marshal(TelegramUpdate{
|
||||
UpdateID: 2,
|
||||
CallbackQuery: &TelegramCallbackQuery{
|
||||
ID: "cb-group",
|
||||
From: TelegramUser{ID: 9002, Username: "viewer", FirstName: "Viewer"},
|
||||
Message: &TelegramMessage{MessageID: 56, Chat: TelegramChat{ID: -100123, Type: "supergroup"}},
|
||||
Data: "adult_toggle",
|
||||
},
|
||||
})
|
||||
if err := bot.HandleWebhook(ctx, update); err != nil {
|
||||
t.Fatalf("handle webhook: %v", err)
|
||||
}
|
||||
if len(callbackPayloads) != 1 {
|
||||
t.Fatalf("answerCallbackQuery count = %d", len(callbackPayloads))
|
||||
}
|
||||
if !callbackPayloads[0].ShowAlert || !strings.Contains(callbackPayloads[0].Text, "群组内按钮面板已禁用") {
|
||||
t.Fatalf("unexpected callback answer: %#v", callbackPayloads[0])
|
||||
}
|
||||
after, _ := repos.User.FindByID(ctx, user.ID)
|
||||
if before == nil || after == nil || before.HideAdult != after.HideAdult {
|
||||
t.Fatalf("group callback should not mutate user adult visibility: before=%#v after=%#v", before, after)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user