107 lines
3.9 KiB
Go
107 lines
3.9 KiB
Go
package main
|
|
|
|
// 钉住组合根侧的接线契约:buildAccountAdapter 构造 qq-obv11 适配器时必须把 channelFactory
|
|
// 手上的 logger 传进去(与 kook/telegram/webhook 同口径,见 cmd/cyrene/channels.go)。缺陷
|
|
// 形态:漏传 ⇒ 适配器自造默认 INFO 兜底 ⇒ 入站帧取证(DEBUG)全部静默丢弃,主人要查的
|
|
// 「群友 @ 没回 / 戳一戳没反应」在日志里一片空白,且与「上游压根没上报」无法区分。
|
|
//
|
|
// 断言走**真实入站路径**:真开一次 http+server 端、真 POST 一条 OneBot 上报,再看注入的
|
|
// 捕获器里有没有 `msg="inbound frame"`。所以只要接线一断,这条测试必红。
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"log/slog"
|
|
"net/http"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
|
|
"git.yeij.top/AskaEth/Cyrene_v2/internal/channel/adapter"
|
|
"git.yeij.top/AskaEth/Cyrene_v2/internal/config"
|
|
"git.yeij.top/AskaEth/Cyrene_v2/plugins/channels/qq_obv11"
|
|
)
|
|
|
|
// logSyncBuf 是并发安全的日志捕获目标:上报由 http.Server 自己的 goroutine 处理,断言在
|
|
// 测试 goroutine 上读。
|
|
type logSyncBuf struct {
|
|
mu sync.Mutex
|
|
buf bytes.Buffer
|
|
}
|
|
|
|
func (b *logSyncBuf) Write(p []byte) (int, error) {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
return b.buf.Write(p)
|
|
}
|
|
|
|
func (b *logSyncBuf) String() string {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
return b.buf.String()
|
|
}
|
|
|
|
// qqObv11WiringFrame 是一条最普通的群消息事件(与 plugins/channels/qq_obv11 的取证测试
|
|
// 同口径):走到 handlePayload 就必然留一行入站帧。
|
|
const qqObv11WiringFrame = `{"post_type":"message","message_type":"group","sub_type":"normal",
|
|
"self_id":10001,"user_id":20002,"group_id":1070898847,
|
|
"raw_message":"hello","message":[{"type":"text","data":{"text":"hello"}}]}`
|
|
|
|
// TestBuildAccountAdapter_QQObv11WiresLoggerIntoInboundForensics 断言注入的 logger 真的
|
|
// 到了适配器手里。捕获器级别设为 DEBUG:取证日志本身是 DEBUG 级,用默认 INFO 的捕获器
|
|
// 「丢了」与「没丢」都看不见,测不出这条接线。
|
|
func TestBuildAccountAdapter_QQObv11WiresLoggerIntoInboundForensics(t *testing.T) {
|
|
buf := &logSyncBuf{}
|
|
log := slog.New(slog.NewTextHandler(buf, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
|
|
|
acct := config.ChannelAccount{Config: map[string]any{
|
|
"transport": "http",
|
|
"mode": "server",
|
|
"listen_addr": "127.0.0.1:0",
|
|
"report_path": "/onebot/report",
|
|
}}
|
|
built, err := buildAccountAdapter("qq-obv11", acct, log)
|
|
if err != nil {
|
|
t.Fatalf("buildAccountAdapter: %v", err)
|
|
}
|
|
ctx := context.Background()
|
|
if cerr := built.Connect(ctx); cerr != nil {
|
|
t.Fatalf("Connect: %v", cerr)
|
|
}
|
|
t.Cleanup(func() { _ = built.Disconnect(context.Background()) })
|
|
|
|
post := "http://" + qqObv11ListenAddr(t, built) + "/onebot/report"
|
|
resp, perr := http.Post(post, "application/json", strings.NewReader(qqObv11WiringFrame))
|
|
if perr != nil {
|
|
t.Fatalf("POST %s: %v", post, perr)
|
|
}
|
|
if cerr := resp.Body.Close(); cerr != nil {
|
|
t.Fatalf("close response body: %v", cerr)
|
|
}
|
|
|
|
if got := buf.String(); !strings.Contains(got, `msg="inbound frame"`) {
|
|
t.Fatalf("注入的 logger 没收到入站帧日志——组合根没把 logger 接进 qq-obv11 适配器?\n捕获到的日志:\n%s", got)
|
|
}
|
|
if got := buf.String(); !strings.Contains(got, "source=plugins/channels/qq_obv11") {
|
|
t.Errorf("入站帧日志缺来源标注:\n%s", got)
|
|
}
|
|
}
|
|
|
|
// qqObv11ListenAddr 取出适配器实际绑定的监听地址(listen_addr 用 :0 让内核挑端口)。
|
|
func qqObv11ListenAddr(t *testing.T, built adapter.PlatformAdapter) string {
|
|
t.Helper()
|
|
named, ok := built.(*namedAdapter)
|
|
if !ok {
|
|
t.Fatalf("适配器类型 = %T, want *namedAdapter", built)
|
|
}
|
|
inner, ok := named.PlatformAdapter.(*qq_obv11.Adapter)
|
|
if !ok {
|
|
t.Fatalf("内层适配器类型 = %T, want *qq_obv11.Adapter", named.PlatformAdapter)
|
|
}
|
|
addr := inner.Addr()
|
|
if addr == "" {
|
|
t.Fatal("适配器没绑定监听地址:http+server 端没起来")
|
|
}
|
|
return addr
|
|
}
|