Files
aiaa-notification-server/internal/adapter/safew_chats_test.go
T
ryan a07963e150 feat: enhance Safew chat handling and testing
- Updated `GroupsFromUpdates` function to return the number of updates processed, improving the polling mechanism.
- Added a new test `TestGroupsFromUpdatesCallbackAndJoinRequest` to validate handling of callback queries and join requests.
- Introduced `safewAllowedUpdates` to specify allowed update types in the polling request, enhancing chat management.
- Implemented `ensureWebhookCleared` method to manage webhook state before polling, improving reliability.
2026-08-15 01:56:12 +08:00

157 lines
4.3 KiB
Go

package adapter
import (
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestGroupsFromUpdatesKeepsGroupsDropsPrivate(t *testing.T) {
body := []byte(`{
"ok": true,
"result": [
{"update_id": 100000001, "message": {"chat": {"id": 10000778141, "type": "group", "title": "测试AI"}}},
{"update_id": 100000002, "message": {"chat": {"id": 11, "type": "private", "first_name": "u"}}},
{"update_id": 100000003, "my_chat_member": {"chat": {"id": 22, "type": "supergroup", "title": "SG", "username": "sg_name"}}}
]
}`)
chats, maxID, _, err := GroupsFromUpdates(body)
if err != nil {
t.Fatal(err)
}
if maxID != 100000003 {
t.Fatalf("maxID=%d", maxID)
}
if len(chats) != 2 {
t.Fatalf("len=%d want 2: %#v", len(chats), chats)
}
byID := map[string]SafewChat{}
for _, c := range chats {
byID[c.ID] = c
}
g := byID["10000778141"]
if g.Type != "group" || g.Title != "测试AI" {
t.Fatalf("group: %#v", g)
}
raw, _ := json.Marshal(g)
var m map[string]any
_ = json.Unmarshal(raw, &m)
if _, ok := m["id"].(string); !ok {
t.Fatalf("id JSON type = %T, want string", m["id"])
}
sg := byID["22"]
if sg.Username == nil || *sg.Username != "sg_name" {
t.Fatalf("username: %#v", sg)
}
}
func TestGroupsFromUpdatesCallbackAndJoinRequest(t *testing.T) {
body := []byte(`{
"ok": true,
"result": [
{"update_id": 1, "callback_query": {"message": {"chat": {"id": 10000778141, "type": "group", "title": "测试AI"}}}},
{"update_id": 2, "chat_join_request": {"chat": {"id": 33, "type": "group", "title": "join-me"}}}
]
}`)
chats, maxID, _, err := GroupsFromUpdates(body)
if err != nil {
t.Fatal(err)
}
if maxID != 2 {
t.Fatalf("maxID=%d", maxID)
}
if len(chats) != 2 {
t.Fatalf("len=%d %#v", len(chats), chats)
}
}
func TestFilterSafewChats(t *testing.T) {
chats := []SafewChat{
{ID: "10000778141", Type: "group", Title: "测试AI"},
{ID: "99", Type: "group", Title: "ops"},
}
got := FilterSafewChats(chats, "测试")
if len(got) != 1 || got[0].ID != "10000778141" {
t.Fatalf("%#v", got)
}
got = FilterSafewChats(chats, "10000778141")
if len(got) != 1 || got[0].Title != "测试AI" {
t.Fatalf("%#v", got)
}
got = FilterSafewChats(chats, "")
if len(got) != 2 {
t.Fatalf("empty q should keep all, got %d", len(got))
}
}
func TestPollGroupChatsSuccess(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/bottok/deleteWebhook" {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"ok":true,"result":true}`))
return
}
if r.URL.Path != "/bottok/getUpdates" {
t.Errorf("path=%s", r.URL.Path)
}
raw, _ := io.ReadAll(r.Body)
var body map[string]any
_ = json.Unmarshal(raw, &body)
if body["timeout"] != float64(0) {
t.Errorf("timeout=%v", body["timeout"])
}
if body["offset"] != float64(5) {
t.Errorf("offset=%v", body["offset"])
}
got, _ := body["allowed_updates"].([]any)
if len(got) == 0 {
t.Errorf("missing allowed_updates: %s", raw)
}
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"ok":true,"result":[{"update_id":10,"message":{"chat":{"id":10000778141,"type":"group","title":"测试AI"}}}]}`))
}))
defer srv.Close()
s := &SafeWSender{apiBase: srv.URL}
chats, next, err := s.PollGroupChats("tok", 5, 0)
if err != nil {
t.Fatal(err)
}
if next != 11 {
t.Fatalf("next=%d want 11", next)
}
if len(chats) != 1 || chats[0].ID != "10000778141" {
t.Fatalf("%#v", chats)
}
}
func TestSafewErrorDescriptionIncludesErrorMsg(t *testing.T) {
got := safewErrorDescription([]byte(`{"ok":false,"description":"BAD_REQUEST","error_msg":"Conflict: terminated by other getUpdates request"}`))
if !strings.Contains(got, "Conflict") {
t.Fatalf("got %q, want error_msg", got)
}
}
func TestPollGroupChatsUnauthorized(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte(`{"ok":false,"error_code":401,"description":"BOT_TOKEN_INVALID"}`))
}))
defer srv.Close()
s := &SafeWSender{apiBase: srv.URL}
_, _, err := s.PollGroupChats("bad", 0, 0)
if err == nil {
t.Fatal("expected error")
}
ae, ok := err.(*SafewAuthError)
if !ok {
t.Fatalf("type %T %v", err, err)
}
if !strings.Contains(ae.Description, "BOT_TOKEN_INVALID") {
t.Fatalf("%q", ae.Description)
}
}