Files
Cyrene_v2/internal/services/gateway/proactive_test.go
T
AskaEth 074ffc4ebf
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
docs(gateway): gateway 剩余文件注释改中文(逐行 1:1,代码零字节改动)
主人 2026-10-03 拍板「注释一律中文」;gateway 至此整包注释中文化完成(本会话共 3 批:
已推库 16 个文件 + 本批剩余文件)。
校验:机械校验(非注释改动行)= 空;剥注释后代码文本逐行比对全等(不一致文件数 0);
全树 go test ./... 58 包 ok / 0 FAIL;交叉编译绿。
2026-10-03 22:28:25 +08:00

124 lines
3.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package gateway
import (
"context"
"testing"
"git.yeij.top/AskaEth/Cyrene_v2/internal/auth"
"git.yeij.top/AskaEth/Cyrene_v2/internal/channel/adapter"
)
// TestHub_SendProactive_OwnerAndAdmin 验证主动推送恰好抵达
// owner/admin 连接并返回投递计数;viewer 或未认证
// (nil claims)连接绝不收到它。
func TestHub_SendProactive_OwnerAndAdmin(t *testing.T) {
t.Parallel()
hb := newTestHub(nil, nil)
owner := newFakeConn(hb, 8)
owner.claims = &auth.Claims{Role: auth.RoleOwner}
admin := newFakeConn(hb, 8)
admin.claims = &auth.Claims{Role: auth.RoleAdmin}
viewer := newFakeConn(hb, 8)
viewer.claims = &auth.Claims{Role: auth.RoleViewer}
bare := newFakeConn(hb, 8) // claims 为 nil:未认证
for _, c := range []*wsConn{owner, admin, viewer, bare} {
hb.register(c)
}
msg := adapter.UnifiedMessage{
Platform: "cyrene-backthink",
ChannelType: adapter.ChannelDirect,
Content: "记得喝水哦",
ContentType: adapter.ContentText,
Sender: adapter.Actor{Role: adapter.RoleSystem, DisplayName: "Cyrene"},
ChannelID: "kook:123",
SenderID: "uid-999",
MessageID: "m-42",
}
n, err := hb.SendProactive(context.Background(), msg)
if err != nil {
t.Fatalf("SendProactive err = %v", err)
}
if n != 2 {
t.Fatalf("count = %d, want 2 (owner+admin; viewer and bare excluded)", n)
}
for _, c := range []*wsConn{owner, admin} {
ev := readFakeFrame(t, c)
if ev.Type != "proactive_message" {
t.Fatalf("frame type = %q, want proactive_message (frame=%+v)", ev.Type, ev)
}
data, ok := ev.Data.(map[string]any)
if !ok {
t.Fatalf("frame data type = %T, want map[string]any", ev.Data)
}
if data["content"] != "记得喝水哦" {
t.Fatalf("frame content = %q, want the proactive text", data["content"])
}
if data["sender"] != "Cyrene" {
t.Fatalf("frame sender = %q, want Cyrene", data["sender"])
}
if data["platform"] != "cyrene-backthink" {
t.Fatalf("frame platform = %q, want cyrene-backthink", data["platform"])
}
}
for _, c := range []*wsConn{viewer, bare} {
if err := connHasNoFrame(c); err != nil {
t.Fatalf("unexpected frame for a non-owner/admin conn: %v", err)
}
}
}
// TestHub_SendProactive_NoOnlineOwner 验证没有存活 owner/admin 连接时
// 计数为零(无错误),使调用方回退到 IM bridge。
func TestHub_SendProactive_NoOnlineOwner(t *testing.T) {
t.Parallel()
hb := newTestHub(nil, nil)
viewer := newFakeConn(hb, 8)
viewer.claims = &auth.Claims{Role: auth.RoleViewer}
hb.register(viewer)
n, err := hb.SendProactive(context.Background(), adapter.UnifiedMessage{Content: "hi"})
if err != nil {
t.Fatalf("SendProactive err = %v", err)
}
if n != 0 {
t.Fatalf("count = %d, want 0", n)
}
}
// TestHub_SendProactive_CancelledContext 验证被取消的 context 拒绝该
// 推送(fail closed)并返回被 wrap 的错误。
func TestHub_SendProactive_CancelledContext(t *testing.T) {
t.Parallel()
hb := newTestHub(nil, nil)
ctx, cancel := context.WithCancel(context.Background())
cancel()
if _, err := hb.SendProactive(ctx, adapter.UnifiedMessage{Content: "hi"}); err == nil {
t.Fatalf("expected a context error, got nil")
}
}
// TestServer_SendProactive_DelegatesToHub 验证 Server.SendProactive 镜像
// hub,使组合根能把网关自身交给汇聚点设置器。
func TestServer_SendProactive_DelegatesToHub(t *testing.T) {
t.Parallel()
env := newEnv(t, nil, false)
c := newFakeConn(env.srv.hub, 8)
c.claims = &auth.Claims{Role: auth.RoleOwner}
env.srv.hub.register(c)
n, err := env.srv.SendProactive(context.Background(), adapter.UnifiedMessage{Content: "hi"})
if err != nil {
t.Fatalf("SendProactive err = %v", err)
}
if n != 1 {
t.Fatalf("count = %d, want 1", n)
}
ev := readFakeFrame(t, c)
if ev.Type != "proactive_message" {
t.Fatalf("frame type = %q, want proactive_message", ev.Type)
}
}